使用单元测试可以隔离开其他与本次开发不相干的诸多因素,普通的jave项目可以在测试类中直接注解@Test标注单元测试方法,当测试项目中测试的方法中有涉及使用spring进行管理bean时,spring提供了一种比较便捷的解决方案。以下以现进行开发的项目环境做说明,将对环境、配置及常见问题进行说明。
项目环境:
开发工具myeclipse,项目管理工具maven,项目为spring batch实现的批处理程序【使用sping进行管理相关bean】
关键配置:
- 在pom.xml文件中增加继承测试使用的依赖【详见代码1】
- 配置单元测试类【详见代码2】
- 运行
1. 可以使用maven进行运行如下图,最好在pom的开发环境中添加插件maven-surefire-plugin【详见代码3】,可以生成报告,不配置的话测试打印日志可能乱码。
2. 也可以通过run as->junit test方式运行
代码1
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
代码2-1
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/applicationContext.xml",
"classpath:spring/common-datasource.xml",
"classpath:spring/common-batch.xml",
"classpath:spring/dataAccessContext-local-dev.xml" })
public abstract class SpringJunitBaseTest {
@Autowired
protected JobLauncher jobLauncher;
@Autowired
@Qualifier("traditPolicyOfBisToNbzJob")
protected Job job;
protected Long startTime;
@Before
public void beforeMethod() {
System.out.println("测试执行前>>>>>>>>");
startTime = System.currentTimeMillis();
}
@After
public void afterMethod() {
System.out.println("测试执行后<<<<<<<<");
Long takeTime = System.currentTimeMillis() - startTime;
StringBuffer takeTimeShow = new StringBuffer("执行结束,总耗时【");
Long minutes = takeTime / 60000;
Long seconds = takeTime % 60000 / 1000;
Long mills = takeTime % 1000;
takeTimeShow.append(minutes + "分" + seconds + "秒" + mills + "毫秒");
takeTimeShow.append("】");
System.out.println(takeTimeShow);
}
@Test
public void test() {
try {
jobLauncher.run(job, getJobParameter());
} catch (JobExecutionAlreadyRunningException e) {
e.printStackTrace();
} catch (JobRestartException e) {
e.printStackTrace();
} catch (JobInstanceAlreadyCompleteException e) {
e.printStackTrace();
} catch (JobParametersInvalidException e) {
e.printStackTrace();
}
}
public abstract JobParameters getJobParameter();
}
代码2-2
@ContextConfiguration(locations = {
"classpath:spring/jobConfig/batchForTraditPolicyOfBisToNbz.xml",
"classpath:spring/jobConfig/batchForTraditPolicyOfBisToNbzBean-dev.xml",
"classpath:spring/dataAccessContext-local2-dev.xml",
"classpath:spring/dataAccessContext-prps-dev.xml" })
public class TraditPolicyOfBisToNbzJobTest extends SpringJunitBaseTest {
@Autowired
@Qualifier("traditPolicyOfBisToNbzJob")
protected Job job;
@Override
public JobParameters getJobParameter() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Date now = new Date();
return new JobParametersBuilder().addString("batchId",
"TRADIT_POLICY_TO_BIS_" + sdf.format(now)).toJobParameters();
}
}
代码3-maven-surefire-plugin插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<extensions>true</extensions>
<version>2.19</version>
<configuration>
<testFailureIgnore>false</testFailureIgnore>
<argLine>${maven.test.jvmargs}</argLine>
<testFailureIgnore>true</testFailureIgnore>
<excludes>
<exclude>**/SpringJunitBaseTest.java</exclude>
</excludes>
</configuration>
</plugin>
代码2说明
在项目做单元测试时,尤其项目较大时,由于每个单元测试之间的差异都不是很大,有很多共同内容,一般做一个抽象在后续的单元测试编写会省时不少,代码也更优雅,以上代码2-1位抽象单元测试类,在上下文配置【ContextConfiguration】上,父子类也存在继承关系【PS:inheritLocations属性:如果设置为false,将屏蔽掉父类中使用该注解指定的配置文件位置,默认为true表示继承父类中使用该注解指定的配置文件位置】。
异常说明 :
java.lang.NoClassDefFoundError: Could not initialize class org.springframework.test.context.junit4.SpringJUnit4ClassRunner
如果你运气不好,很可能碰到这个异常,单元测试失败,什么原因?junit跟spring test有版本兼容问题,特别需要注意。以上配置中的junit跟spring test是兼容的。