afterclass_通过beforeClass和afterClass设置增强Spring Test Framework

afterclass

如何允许实例方法作为JUnit BeforeClass行为运行

JUnit允许您在所有测试方法调用之前和之后一次在类级别上设置方法。 但是,通过有意设计,它们将其限制为仅使用@BeforeClass@AfterClass批注的静态方法。 例如,以下简单演示演示了典型的Junit设置:

package deng.junitdemo;import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;public class DemoTest {@Testpublic void testOne() {System.out.println('Normal test method #1.');}@Testpublic void testTwo() {System.out.println('Normal test method #2.');}@BeforeClasspublic static void beforeClassSetup() {System.out.println('A static method setup before class.');}@AfterClasspublic static void afterClassSetup() {System.out.println('A static method setup after class.');}
}

并应产生以下输出:

A static method setup before class.
Normal test method #1.
Normal test method #2.
A static method setup after class.

在大多数情况下,此用法都可以,但是有时候您想使用非静态方法来设置测试。 稍后,我将向您展示更详细的用例,但现在,让我们看看如何首先使用JUnit解决这个顽皮的问题。 我们可以通过使测试实现一个提供before和after回调的Listener来解决此问题,并且需要挖掘JUnit来检测此Listener来调用我们的方法。 这是我想出的解决方案:

package deng.junitdemo;import org.junit.Test;
import org.junit.runner.RunWith;@RunWith(InstanceTestClassRunner.class)
public class Demo2Test implements InstanceTestClassListener {@Testpublic void testOne() {System.out.println('Normal test method #1');}@Testpublic void testTwo() {System.out.println('Normal test method #2');}@Overridepublic void beforeClassSetup() {System.out.println('An instance method setup before class.');}@Overridepublic void afterClassSetup() {System.out.println('An instance method setup after class.');}
}

如上所述,我们的监听器是一个简单的合同:

package deng.junitdemo;public interface InstanceTestClassListener {void beforeClassSetup();void afterClassSetup();
}

我们的下一个任务是提供将触发设置方法的JUnit运行器实现。

package deng.junitdemo;import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;public class InstanceTestClassRunner extends BlockJUnit4ClassRunner {private InstanceTestClassListener InstanceSetupListener;public InstanceTestClassRunner(Class<?> klass) throws InitializationError {super(klass);}@Overrideprotected Object createTest() throws Exception {Object test = super.createTest();// Note that JUnit4 will call this createTest() multiple times for each// test method, so we need to ensure to call 'beforeClassSetup' only once.if (test instanceof InstanceTestClassListener && InstanceSetupListener == null) {InstanceSetupListener = (InstanceTestClassListener) test;InstanceSetupListener.beforeClassSetup();}return test;}@Overridepublic void run(RunNotifier notifier) {super.run(notifier);if (InstanceSetupListener != null)InstanceSetupListener.afterClassSetup();}
}

现在我们从事业务。 如果我们在测试之上运行,它应该会给我们类似的结果,但是这次我们使用的是实例方法!

An instance method setup before class.
Normal test method #1
Normal test method #2
An instance method setup after class.


一个具体的用例:使用Spring Test Framework

现在,让我向您展示一个上面的真实用例。 如果使用Spring Test Framework,通常会设置一个这样的测试,以便可以将测试夹具作为成员实例注入。

package deng.junitdemo.spring;import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;import java.util.List;import javax.annotation.Resource;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SpringDemoTest {@Resource(name='myList')private List<String> myList;@Testpublic void testMyListInjection() {assertThat(myList.size(), is(2));}
}

您还需要在同一包下的spring xml才能运行:

<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns='http://www.springframework.org/schema/beans'xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd'><bean id='myList' class='java.util.ArrayList'><constructor-arg><list><value>one</value><value>two</value></list></constructor-arg></bean>
</beans>

非常注意成员实例List<String> myList 。 运行JUnit测试时,Spring将注入该字段,并且可以在任何测试方法中使用它。 但是,如果您想一次性设置一些代码并获得对Spring注入字段的引用,那么您很不幸。 这是因为JUnit @BeforeClass将强制您的方法为静态方法。 如果您将字段设为静态,则在测试中无法使用Spring注入!

现在,如果您是经常使用Spring的用户,您应该知道Spring Test Framework已经为您提供了一种处理此类用例的方法。 这是一种使用Spring样式进行类级别设置的方法:

package deng.junitdemo.spring;import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;import java.util.List;import javax.annotation.Resource;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(listeners = {DependencyInjectionTestExecutionListener.class, SpringDemo2Test.class})
@ContextConfiguration
public class SpringDemo2Test extends AbstractTestExecutionListener {@Resource(name='myList')private List<String> myList;@Testpublic void testMyListInjection() {assertThat(myList.size(), is(2));}@Overridepublic void afterTestClass(TestContext testContext) {List<?> list = testContext.getApplicationContext().getBean('myList', List.class);assertThat((String)list.get(0), is('one'));}@Overridepublic void beforeTestClass(TestContext testContext) {List<?> list = testContext.getApplicationContext().getBean('myList', List.class);assertThat((String)list.get(1), is('two'));}
}

如您所见,Spring提供了@TestExecutionListeners批注,以允许您编写任何侦听器,并且在其中将具有对TestContext的引用,该引用具有ApplicationContext以便您获取注入的字段引用。 这行得通,但我觉得它不是很优雅。 当您注入的字段已经可以用作字段时,它会强制您查找bean。 但是除非您通过TestContext参数,否则您将无法使用它。

现在,如果您混合了开始时提供的解决方案,我们将看到更漂亮的测试设置。 让我们来看看它:

package deng.junitdemo.spring;import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;import java.util.List;import javax.annotation.Resource;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;import deng.junitdemo.InstanceTestClassListener;@RunWith(SpringInstanceTestClassRunner.class)
@ContextConfiguration
public class SpringDemo3Test implements InstanceTestClassListener {@Resource(name='myList')private List<String> myList;@Testpublic void testMyListInjection() {assertThat(myList.size(), is(2));}@Overridepublic void beforeClassSetup() {assertThat((String)myList.get(0), is('one'));}@Overridepublic void afterClassSetup() {assertThat((String)myList.get(1), is('two'));}
}

现在,JUnit仅允许您使用单个Runner ,因此我们必须扩展Spring的版本以插入之前的操作。

package deng.junitdemo.spring;import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.InitializationError;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import deng.junitdemo.InstanceTestClassListener;public class SpringInstanceTestClassRunner extends SpringJUnit4ClassRunner {private InstanceTestClassListener InstanceSetupListener;public SpringInstanceTestClassRunner(Class<?> clazz) throws InitializationError {super(clazz);}@Overrideprotected Object createTest() throws Exception {Object test = super.createTest();// Note that JUnit4 will call this createTest() multiple times for each// test method, so we need to ensure to call 'beforeClassSetup' only once.if (test instanceof InstanceTestClassListener && InstanceSetupListener == null) {InstanceSetupListener = (InstanceTestClassListener) test;InstanceSetupListener.beforeClassSetup();}return test;}@Overridepublic void run(RunNotifier notifier) {super.run(notifier);if (InstanceSetupListener != null)InstanceSetupListener.afterClassSetup();}
}

这应该够了吧。 运行测试将使用以下输出:

12:58:48 main INFO  org.springframework.test.context.support.AbstractContextLoader:139 | Detected default resource location 'classpath:/deng/junitdemo/spring/SpringDemo3Test-context.xml' for test class [deng.junitdemo.spring.SpringDemo3Test].
12:58:48 main INFO  org.springframework.test.context.support.DelegatingSmartContextLoader:148 | GenericXmlContextLoader detected default locations for context configuration [ContextConfigurationAttributes@74b23210 declaringClass = 'deng.junitdemo.spring.SpringDemo3Test', locations = '{classpath:/deng/junitdemo/spring/SpringDemo3Test-context.xml}', classes = '{}', inheritLocations = true, contextLoaderClass = 'org.springframework.test.context.ContextLoader'].
12:58:48 main INFO  org.springframework.test.context.support.AnnotationConfigContextLoader:150 | Could not detect default configuration classes for test class [deng.junitdemo.spring.SpringDemo3Test]: SpringDemo3Test does not declare any static, non-private, non-final, inner classes annotated with @Configuration.
12:58:48 main INFO  org.springframework.test.context.TestContextManager:185 | @TestExecutionListeners is not present for class [class deng.junitdemo.spring.SpringDemo3Test]: using defaults.
12:58:48 main INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315 | Loading XML bean definitions from class path resource [deng/junitdemo/spring/SpringDemo3Test-context.xml]
12:58:48 main INFO  org.springframework.context.support.GenericApplicationContext:500 | Refreshing org.springframework.context.support.GenericApplicationContext@44c9d92c: startup date [Sat Sep 29 12:58:48 EDT 2012]; root of context hierarchy
12:58:49 main INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory:581
| Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@73c6641: defining beans [myList,org.springframework.context.annotation.
internalConfigurationAnnotationProcessor,org.
springframework.context.annotation.internalAutowiredAnnotationProcessor,org
.springframework.context.annotation.internalRequiredAnnotationProcessor,org.
springframework.context.annotation.internalCommonAnnotationProcessor,org.
springframework.context.annotation.
ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
12:58:49 Thread-1 INFO  org.springframework.context.support.GenericApplicationContext:1025 | Closing org.springframework.context.support.GenericApplicationContext@44c9d92c: startup date [Sat Sep 29 12:58:48 EDT 2012]; root of context hierarchy
12:58:49 Thread-1 INFO  org.springframework.beans.factory.support.
DefaultListableBeanFactory:433 
| Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@
73c6641: defining beans [myList,org.springframework.context.annotation.
internalConfigurationAnnotationProcessor,org.springframework.
context.annotation.internalAutowiredAnnotationProcessor,org.springframework.
context.annotation.internalRequiredAnnotationProcessor,org.springframework.
context.annotation.internalCommonAnnotationProcessor,org.springframework.
context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy

显然,输出在这里没有显示任何有趣的内容,但是测试应该在所有声明通过的情况下运行。 关键是,现在我们有一种更优雅的方法来调用类级别的测试之前和之后的测试,并且它们可以是允许Spring注入的实例方法。

下载演示代码

您可能会从我的沙箱中获得一个正常运行的Maven项目中的演示代码

参考: A程序员杂志博客上的JCG合作伙伴 Zemian Deng提供的beforeClass和afterClass设置增强了Spring Test Framework 。


翻译自: https://www.javacodegeeks.com/2012/10/enhancing-spring-test-framework-with.html

afterclass

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/352713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

联想服务器支持esxi版本,联想中国(Lenovo China)_服务频道_服务政策

Lenovo ThinkServer Partner Pack for VMware vCenter重要通知:ThinkServer RD350/RD450/RD550/RD650/TD350 中Lenovo ThinkServer Partner Pack 被Lenovo XClarity Integrator for VMware vCenter所取代, 请点击如下链接获取:Lenovo XClarity Integrator for VMware vCenter 不…

什么是凸组合?

问&#xff1a;什么是凸组合&#xff1f; 答&#xff1a;凸组合是指&#xff0c;假设x1,x2,...,xn是一组对象&#xff08;要根据讨论问题的背景来确定&#xff09;&#xff0c;a1,a2,...,an是n个常数&#xff0c;并且满足a1a2...an1&#xff0c;那么a1x1a2x2...anxn&#xff0…

字魂35号经典雅黑_2020:上海不锈钢黑钛线条行业

2020&#xff1a;上海不锈钢黑钛线条行业 不锈钢花格可以单独制作&#xff0c;也可以连通整个产品以其制作&#xff0c;如屏风。经热浸镀锌处理后的不锈钢屏风构件隔断&#xff0c;栏杆&#xff0c;窗户&#xff0c;门套&#xff0c;拱门&#xff0c;装饰摆件&#xff0c;灯罩等…

MySQL(一)基础操作

MySQL基础操作 一、MySQL数据库管理 1.登入 mysql -u root -p 然后输入密码 2.查看当前MySQL会话使用的字符集 show variables like character%; 显示如下&#xff1a; mysql> show variables like character%;-----------------------------------------------------------…

Spring管理的Hibernate事件监听器

Hibernate提供事件监听器作为其SPI的一部分。 您可以将您的侦听器挂接到许多事件&#xff0c;包括插入前&#xff0c;插入后&#xff0c;删除前&#xff0c;刷新等。 但是有时在这些侦听器中&#xff0c;您想使用spring依赖项。 我之前已经写过有关如何执行此操作的文章 &…

通过bios修改服务器ipmi配置,Dell服务器之配置ipmi远程console管理

1.启动服务器&#xff0c;按F2键进入BIOS设置Serial Communication:Serial Communication......On with Console Redirection via COM2External Serial Connector...COM22.进入系统&#xff0c;修改/boot/grub/menu.1stdefault2timeout15kernel /boot/kernel ro root/dev/sda1 …

分形艺术照

分形艺术照编辑 分形艺术照其实是分形艺术图形的另一种称呼。分形艺术图形的创作依赖于计算机强大的计算能力&#xff0c;将数学公式迭代运算&#xff0c;最终把计算结果以图形显示出来。这样得到的图形&#xff0c;结合创作者的色彩搭配以及变换组合&#xff0c;能产生出具有强…

热像仪 二次开发 c++_重庆多功能红外线热像仪方案

重庆多功能红外线热像仪方案 yuve4uj重庆多功能红外线热像仪方案 同时&#xff0c;中文人机对话对识别与合成、自然语言理解、对话管理以及自然语言生成等研究起到的推动作用。月日&#xff0c;我们开始建立个智能方舱&#xff0c;目的是防止武昌的工作人员感染病。该病房于月日…

C语言-第8课 - 注释符号

第8课 - 注释符号 C语言中的符号符号 名称 符号 名称 符号 名称 符号 名称 , 逗号 ( 左圆括号 ^ xor(异或) \ 反斜杠 . 圆点 ) 右圆括号 - 减号 ~ 波折号 ; 分号 [ 左方括号 < 左尖括号 # 井号 : 冒号 ] 右方括号 > 右尖括号 &…

运行错误5无效的过程调用或参数_FANUC系统常用参数汇总

FANUC机床常用参数简介1、1-999:有关通讯、远程诊断、数据服务参数。如&#xff1a;0000#11程序输出格式为ISO代码10310数据传送波特率204 I/O通讯口&#xff08;用CF卡&#xff09;138#71用存贮卡DNC2.1000-1200&#xff1a;轴控制/设定单位的参数。如&#xff1a;1001.0公/英…

上传文件ajax,ajax 文件上传

ajax 文件上传用户名:文件:

WPF 实现水纹效果

WPF 实现水纹效果 原文:WPF 实现水纹效果鼠标滑过产生水纹&#xff0c;效果图如下&#xff1a; XMAL就放置了一个img标签 后台主要代码 窗体加载&#xff1a; private void Window_Loaded(object sender, RoutedEventArgs e) { Bitmap bmp Properties.Resources.water; ww ne…

OutOfMemoryError:无法创建新的本机线程–神秘化的问题

正如您从我以前的教程和案例研究中可能已经看到的那样&#xff0c;要确定和解决Java Heap Space OutOfMemoryError问题可能很复杂。 我从Java EE生产系统中观察到的常见问题之一是OutOfMemoryError&#xff1a;无法创建新的本机线程&#xff1b; HotSpot JVM无法进一步创建新的…

Linux makefile 教程 非常详细,且易懂

最近在学习Linux下的C编程&#xff0c;买了一本叫《Linux环境下的C编程指南》读到makefile就越看越迷糊&#xff0c;可能是我的理解能不行。 于是google到了以下这篇文章。通俗易懂。然后把它贴出来&#xff0c;方便学习。 后记&#xff0c;看完发现这篇文章和《Linux环境下的C…

java的string访问某个元素_C#深究.net常用的23种设计模式之访问者模式(Vistor Pattern)...

一、引言在上一篇博文中分享了责任链模式&#xff0c;责任链模式主要应用在系统中的某些功能需要多个对象参与才能完成的场景。在这篇博文中&#xff0c;我将为大家分享我对访问者模式的理解。二、访问者模式介绍2.1 访问者模式的定义访问者模式是封装一些施加于某种数据结构之…

卸载 系统打印服务器,win10系统打印机驱动卸载不掉的方案介绍

win10系统使用久了&#xff0c;好多网友反馈说win10系统打印机驱动卸载不掉的问题&#xff0c;非常不方便。有什么办法可以永久解决win10系统打印机驱动卸载不掉的问题&#xff0c;面对win10系统打印机驱动卸载不掉的图文步骤非常简单&#xff0c;只需要1、开始-设备和打印机&a…

1007

package com.company;import java.util.ArrayList; import java.util.Scanner;public class Main {public static void main(String[] args) {// write your code hereScanner scnew Scanner(System.in);int Nsc.nextInt();int[] numnew int[N];//N以内的所有数int i;ArrayList…

Apache ActiveMQ中的消息级别授权

尽管上一篇文章介绍了“代理级身份验证”&#xff0c;但该博文是关于消息级更严格的授权的。 我在现实生活中的项目中并没有这么精细的授权&#xff0c;但是我想自己做&#xff0c;并为读者提供一个教程&#xff0c;以扩展他们对ActiveMQ中安全性的了解并简化他们的工作。 有…

14章总结

一.lambda表达式 1.lambda表达式简介 lambda表达式不能独立执行&#xff0c;因此必须实现函数式接口&#xff0c;并且会返回一个函数式接口的对象。 语法&#xff1a; ()->结果表达式 参数->结果表达式 (参数1&#xff0c;参数2&#xff0c;...&#xff0c;参数n)->…

一个最简单的Makefile例子(转)

原文地址&#xff1a;http://hi.baidu.com/hellosim/blog/item/42e78341b40c3e8db2b7dce3.html 转载请注明出处 1.hello.c #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } 2.Makefile hello : hello.o cc -o hello h…