8.3 Spring應用的單元測試
8.3.1
單元測試如今愈來愈被普遍重視起來,而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);
}
}
這樣就能夠在方法返回以前將測試數據回滾,以保證下次單元測試的成功。