在 ecipse 里 Spring 框架中进行 JUnit 单元测试
测试对于保证软件开发质量有着非常重要的作用,单元测试更是必不可少, JUnit 是一个非常强大的单元测试包,可以对一个 / 多个类的单个 / 多个方法测试,还可以将不同的 TestCase 组合成 TestSuit ,使测试任务自动化。 Eclipse 同样集成了 JUnit ,可以非常方便地编写 TestCase 。
一、 JUnit 核心
JUnit 的目的是协助您进行单元测试( Unit Test ),并鼓励您先写测试。
JUnit 包括了以下的特性:
对预期结果作断言
提供测试装备的生成与销毁
易于组织与执行测试
图型与文字介面的测试器
JUnit 的核心类:TestCase、TestSuite以及BaseTestRunner,其中用的最多的就是TestCase,当需要多个TestCase的时候就要创建一个TestSuite,而运行TestSuite则要创建TestRunner,其关系如下:
核心类定义:
TestCase (测试用例) —— 扩展了JUnit的TestCase类的类。它以testXXX方法的形式包含一个或多个测试。一个test case把具有公共行为的测试归入一组。在本书的后续部分,当我们提到测试的时候,我们指的是一个testXXX方法;当我们提及test case的时候,我们指的是一个继承自TestCase的类,也就是一组测试。
TestSuite (测试集合 )——一组测试。一个test suite是把多个相关测试归入一组的便捷方式。例如,如果你没有为TestCase定义一个test suite,那么JUnit就会自动提供一个test suite,包含TestCase中所有的测试(本书稍后会细说)。
TestRunner (测试运行器 )——执行test suite的程序。JUnit提供了几个test runner,你可以用它们来执行你的测试。没有TestRunner接口,只有一个所有test runner都继承的BaseTestRunner。因此,当我们编写TestRunner的时候,我们实际上指的是任何继承BaseTestRunner的test runner类。
其中TesetCase主要有10个自己的方法:
二、下面就以Eclipse中单个TestCase为例子讲一下普通的JUnit测试:
首先我们创建一个 Java 工程,添加一个 example.Hello 类,首先我们给 Hello 类添加一个 abs() 方法,作用是返回绝对值:
下一步,我们准备对这个方法进行测试,确保功能正常。选中 Hello.java ,右键点击,选择 New->JUnit Test Case :
Eclipse 会询问是否添加 junit.jar 包,确定后新建一个 HelloTest 类,用来测试 Hello 类。
选中 setUp() 和 tearDown() ,然后点击 “Next” :
选择要测试的方法,我们选中 abs(int) 方法,完成后在 HelloTest.java 中输入:
JUnit 会以以下顺序执行测试:(大致的代码)
try { |
setUp() 是建立测试环境,这里创建一个 Hello 类的实例; tearDown() 用于清理资源,如释放打开的文件等等。以 test 开头的方法被认为是测试方法, JUnit 会依次执行 testXxx() 方法。在 testAbs() 方法中,我们对 abs() 的测试分别选择正数,负数和 0 ,如果方法返回值与期待结果相同,则 assertEquals 不会产生异常。
如果有多个 testXxx 方法, JUnit 会创建多个 XxxTest 实例,每次运行一个 testXxx 方法, setUp() 和 tearDown() 会在 testXxx 前后被调用,因此,不要在一个 testA() 中依赖 testB() 。
直接运行 Run->Run As->JUnit Test ,就可以看到 JUnit 测试结果:
绿色表示测试通过,只要有 1 个测试未通过,就会显示红色并列出未通过测试的方法。可以试图改变 abs() 的代码,故意返回错误的结果(比如 return n+1; ),然后再运行 JUnit 就会报告错误。
三、在 Spring 中进行 DAO 测试
Spring 提供了下列一些特定的JUnit框架扩展:
AbstractDependencyInjectionSpringContextTests— 这是一个针对所有测试的超类,其具体使用依赖于Spring上下文。
AbstractSpringContextTests— 这是一个针对所有的JUnit测试情形的超类。它使用一个Spring上下文。并且,一般在测试中不是直接使用它,而是使用AbstractDependencyInjectionSpringContextTests或者AbstractTransactionalSpringContextTests这样的派生类。
AbstractTransactionalSpringContextTests— 这是一个针对所有测试的超类,我们一般把它应用在事务相关的测试中。注意,一旦完成每个测试它就会正常地回滚事务;而且你需要重载onSetUpInTransaction和onTearDownInTransaction方法以便手工开始并提交事务。
AbstractTransactionalDataSourceSpringContextTests— 这是AbstractTransactionalSpringContextTests的一个子类,它使用了Spring的基于JDBC的jdbcTemplate工具类。
所有上面这些扩展将极大程度地简化在测试时对于相关操作的依赖性注入和事务管理。
下面就以一个用户 DAO 类 HibernateUserDao 类中的一个方法 getPasswordByName(String userName) 进行测试作为例子,其中的输入就是用户名,输出就是用户密码:
测试类:
//HibernateUserDAOTest.java
public class HibernateUserDAOTest extends AbstractTransactionalDataSourceSpringContextTests
{
ApplicationContext applicationContext ;
HibernateUserDAO hub ;
@Override
protected String[] getConfigLocations()
{
String[] config= new String[]{ "file:D:\\RfidStock2\\WebRoot\\WEB-INF\\classes\\applicationContext.xml" };
return config;
}
public ApplicationContext getContext(String[] filePath)
{
return new ClassPathXmlApplicationContext(filePath);
}
public void testConfig() {
assertNotNull( "spring-mock context has bean init()" , this .getConfigLocations());
}
@Test
public final void testGetPasswordByName() throws BaseException
{
hub =(HibernateUserDAO)getContext(getConfigLocations()).getBean( "hibernateUserDAO" );
assertEquals( "234" , hub . getPasswordByName ( "42" ));
}
public static void main(String[] args)
{
TestRunner.run((Class<? extends TestCase>) HibernateUserDAO. class );
}
}
在 Spring 下由于要驱动 Spring ,所以测试类要继承 AbstractTransactionalDataSourceSpringContextTests 类,需要实现一个方法 String[] getConfigLocations() ,用这个方法来获取 Spring 的配置文件,然后我通过写 getContext(String[] filePath) 这个方法来获取 Spring 的上下文,在这里我们要获取待测试对象有两种方法一种就是 setHibernateUserDAO() 和 getHibernateUserDAO() 方法,另外一种就是通过上下文提取配置文件中定义的 Bean ,然后再获取具体的方法。
这个就是测试结果: