Spring应用的单元测试
单元测试现在越来越被广泛重视起来,而Spring更是将时下比较流行的Junit开元测试框架进行整合下面我简单的介绍一下在Sping中该如何对代码进行单元测试(本节会认为读者已经具备了Junit基础方面的知识)。按照Spring的推荐,在单元测试时不应该依赖于Spring容器,也就是说不应该在单元测试是启动ApplicationContext并从中获取Bean,相反应该通过模拟对象完成单元测试。而Spring就提供了这样一个类供大家继承。下面来看看示例代码:
1)自动装配的测试用例
代码清单1
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Service;
import
com.tony.web.dao.FooDao;
@Service
public
class
FooService {
@Autowired
private
FooDao
dao
;
public
String save(String name){
if
(name ==
null
||
""
.equals(name))
throw
new
RuntimeException(
"Name is null"
);
return
dao
.save(name);
}
}
import
org.springframework.stereotype.Repository;
@Repository
public
class
FooDao {
public
String save(String name){
return
"success"
;
}
}
import
org.springframework.test.
AbstractDependencyInjectionSpringContextTests;
import
com.tony.web.service.FooService;
public
class
MyTest
extends
AbstractDependencyInjectionSpringContextTests{
protected
FooService
fooService
;
//set
方法
public
void
setFooService(FooService fooService) {
this
.
fooService
= fooService;
}
//
指定
Spring
配置文件的位置
protected
String[] getConfigLocations(){
return
new
String[]{
"spring-config-beans.xml"
};
}
//
测试方法
public
void
testSave(){
String str =
this
.
fooService
.save(
"Tony"
);
System.
out
.print(str);
assertEquals(
"success"
, str);
}
}
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
beans
xmlns
=
"http://...
>
<
context:component-scan
base-package
=
"com.tony"
/>
</
beans
>
代码清单
1
中定义了
FooService.java
和
FooDao.java
两个
Bean
已经使用
@Autowired
进行了装配,我们的单元测试类
MyTest
继承了
AbstractDependencyInjectionSpringContextTests
类,配置好
fooService
的
set
方法并且指定
Spring
配置文件的位置后,当测试用例运行时我们需要的
fooService
会自动注入进来,我们只要在
testSave
方法中直接使用就可以了,还有两外一种写法
代码清单
2
public
class
MyTest
extends
AbstractDependencyInjectionSpringContextTests{
protected
FooService
fooService
;
public
MyTest(){
//
启用直接对属性变量进行注入的机制
this
.setPopulateProtectedVariables(
true
);
}
protected
String[] getConfigLocations(){
return
new
String[]{
"spring-config-beans.xml"
};
}
public
void
testSave(){
String str =
this
.
fooService
.save(
"Tony"
);
System.
out
.print(str);
assertEquals(
"success"
, str);
}
}
代码清单
2
中我们移除了
set
方法,增加了一个构造函数,在构造函数中调用父类的方法启用直接对属性变量进行注入的机制。有时我们测试的时候会操作数据库插入一条记录,由于我们不会每次都修改测试的数据,当我们再次插入同样的数据时数据库肯定会要报错了,此时我们需要既能测试又能不让测试的数据在数据库中起作用,
Spring
就知道我们的这个需要,为我们准备了
AbstractTransactionalSpringContextTests
这个类。
代码清单
3
import
org.springframework.test.
AbstractTransactionalSpringContextTests;
import
com.tony.web.service.FooService;
public
class
MyTest
extends
AbstractTransactionalSpringContextTests{
protected
FooService
fooService
;
public
MyTest(){
this
.setPopulateProtectedVariables(
true
);
}
protected
String[] getConfigLocations(){
return
new
String[]{
"spring-config-beans.xml"
};
}
//
测试方法中的数据操作将在方法返回前被回滚
,
不会对数据库产生永久性数据操作
,
下一
//
次运行该测试方法时
,
依旧可以成功运行
.
public
void
testSave(){
String str =
this
.
fooService
.save(
"Tony"
);
System.
out
.print(str);
assertEquals(
"success"
, str);
}
}
这样就可以在方法返回之前将测试数据回滚,以保证下次单元测试的成功。