单元测试在我们的软件开发整个流程中占有举足轻重的地位,我们可以通过编写单元测试来提高开发的效率、验证程序的有效性,并且减少程序的bug。每一样东西都有两面性,有优点也有缺点,先来说说Junit的优点。
1、提供API以便创建可重复的带有清晰的通过/不通过的结果的单元测试;
2、方便的组织、运行测试和展示结果;
3、可以把多个测试分组打包,成批处理;
4、添加,删除,屏蔽测试方法,不影响其他的测试方法;
5、减少重复工作,提高开发效率。
Junit提供一系列的方法、注解,方便我们进行单元测试的同时,也可以很直观地观察到测试结果。
@Test(expected=...)注解:
此注释标签的含义是,这是一个测试,期待一个异常的发生,期待的异常通过 xxx.class 标识,这个注解可以很方便地验证方法所产生的异常,如果产生期待的异常,则测试通过,否则测试失败;
@Test(timeout=...)注解:
可以给测试方法指定超时时间(毫秒级别),当测试方法的执行时间超过此值,则失败。
eg:
@Test
@Ignore
@Repeat(5)
public void testInsertException() {
service.insertIfNotExist(null);
}
不可否认,在实际应用中,Junit还是有一些不足之处,有以下几点:
1、每次运行,都需要加载所需要的配置;
2、对数据库的操作无法进行回滚;
3、需要添加获取bean实例的代码,也就是无法自动注入。
另外,JUnit是不支持多线程代码的测试的,主线程运行完之后就结束整个测试了。如果想要实现多线程执行,需要继承Runner类,自己实现一个运行环境类。
接下来说说spring-test,spring-test的功能比较强大,可以与Junit完美集成,可以弥补刚刚说到的几个Junit的缺点。Spring 与 Junit 的集成也比较简单,只需在pom.xml中添加以下配置即可。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
如果应用中已经使用到Junit,那么在与spring-test集成的时候。原先的方法和注解都不需要改变,只需要在类的声明处,通过@Run With (Spring JUnit4 Class Runner.class)来启动 Spring 对测试类的支持,通过@Context Configuration注释标签来指定 Spring 配置文件或者配置类的位置,再使用@Transactional 用来启用自动的事务管理即可。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations ={"file\:D:/xxx/xxx/src/main/webapp/WEB-INF/applicationContext.xml"})
@Transactional
public abstract class AbstractTestCase extends TestCase{
……
}
spring-test还支持配置文件的缓存,使用@Dirties Context注解进行配置,缺省情况下,Spring 测试框架一旦加载applicationContext后,将一直缓存,不会改变。但由于Spring允许在运行期修改 applicationContext的定义。例如在运行期获取 applicationContext,然后调用registerSingleton方法来动态的注册新的bean。这样的情况下如果我们还使用Spring测试框架的被修改过applicationContext,则会带来测试问题,我们必须能够在运行期重新加载 applicationContext。这个时候,我们可以在测试类或者方法上注释: @Dirties Context,作用如下:
如果定义在类上(缺省),则在此测试类运行完成后,重新加载 applicationContext
如果定义在方法上,即表示测试方法运行完成后,重新加载 applicationContext。
最后,再说说使用Junit给我们带来的好处:
1、junit+spring-test整合单元测试,无需启动容器,测试更加便捷。
2、通过单元测试,由简及繁,降低复杂项目集成风险。
3、调整代码,通过已有测试用例,快速检查结果,降低测试城。