在
ecipse
里
Spring
框架中進(jìn)行
JUnit
單元測(cè)試
測(cè)試對(duì)于保證軟件開(kāi)發(fā)質(zhì)量有著非常重要的作用,單元測(cè)試更是必不可少,
JUnit
是一個(gè)非常強(qiáng)大的單元測(cè)試包,可以對(duì)一個(gè)
/
多個(gè)類(lèi)的單個(gè)
/
多個(gè)方法測(cè)試,還可以將不同的
TestCase
組合成
TestSuit
,使測(cè)試任務(wù)自動(dòng)化。
Eclipse
同樣集成了
JUnit
,可以非常方便地編寫(xiě)
TestCase
。
一、????????????
JUnit
核心
JUnit
的目的是協(xié)助您進(jìn)行單元測(cè)試(
Unit Test
),并鼓勵(lì)您先寫(xiě)測(cè)試。
JUnit
包括了以下的特性:
對(duì)預(yù)期結(jié)果作斷言
提供測(cè)試裝備的生成與銷(xiāo)毀
易于組織與執(zhí)行測(cè)試
圖型與文字介面的測(cè)試器
JUnit
的核心類(lèi):TestCase、TestSuite以及BaseTestRunner,其中用的最多的就是TestCase,當(dāng)需要多個(gè)TestCase的時(shí)候就要?jiǎng)?chuàng)建一個(gè)TestSuite,而運(yùn)行TestSuite則要?jiǎng)?chuàng)建TestRunner,其關(guān)系如下:
核心類(lèi)定義:
??????? TestCase
(測(cè)試用例)
——
擴(kuò)展了JUnit的TestCase類(lèi)的類(lèi)。它以testXXX方法的形式包含一個(gè)或多個(gè)測(cè)試。一個(gè)test case把具有公共行為的測(cè)試歸入一組。在本書(shū)的后續(xù)部分,當(dāng)我們提到測(cè)試的時(shí)候,我們指的是一個(gè)testXXX方法;當(dāng)我們提及test case的時(shí)候,我們指的是一個(gè)繼承自TestCase的類(lèi),也就是一組測(cè)試。
???????TestSuite
(測(cè)試集合
)——一組測(cè)試。一個(gè)test suite是把多個(gè)相關(guān)測(cè)試歸入一組的便捷方式。例如,如果你沒(méi)有為TestCase定義一個(gè)test suite,那么JUnit就會(huì)自動(dòng)提供一個(gè)test suite,包含TestCase中所有的測(cè)試(本書(shū)稍后會(huì)細(xì)說(shuō))。
????????TestRunner
(測(cè)試運(yùn)行器
)——執(zhí)行test suite的程序。JUnit提供了幾個(gè)test runner,你可以用它們來(lái)執(zhí)行你的測(cè)試。沒(méi)有TestRunner接口,只有一個(gè)所有test runner都繼承的BaseTestRunner。因此,當(dāng)我們編寫(xiě)TestRunner的時(shí)候,我們實(shí)際上指的是任何繼承BaseTestRunner的test runner類(lèi)。
其中TesetCase主要有10個(gè)自己的方法:
二、下面就以Eclipse中單個(gè)TestCase為例子講一下普通的JUnit測(cè)試:
???
首先我們創(chuàng)建一個(gè)
Java
工程,添加一個(gè)
example.Hello
類(lèi),首先我們給
Hello
類(lèi)添加一個(gè)
abs()
方法,作用是返回絕對(duì)值:
下一步,我們準(zhǔn)備對(duì)這個(gè)方法進(jìn)行測(cè)試,確保功能正常。選中
Hello.java
,右鍵點(diǎn)擊,選擇
New->JUnit Test Case
:
Eclipse
會(huì)詢(xún)問(wèn)是否添加
junit.jar
包,確定后新建一個(gè)
HelloTest
類(lèi),用來(lái)測(cè)試
Hello
類(lèi)。
選中
setUp()
和
tearDown()
,然后點(diǎn)擊
“Next”
:
選擇要測(cè)試的方法,我們選中
abs(int)
方法,完成后在
HelloTest.java
中輸入:
JUnit
會(huì)以以下順序執(zhí)行測(cè)試:(大致的代碼)
try { |
setUp()
是建立測(cè)試環(huán)境,這里創(chuàng)建一個(gè)
Hello
類(lèi)的實(shí)例;
tearDown()
用于清理資源,如釋放打開(kāi)的文件等等。以
test
開(kāi)頭的方法被認(rèn)為是測(cè)試方法,
JUnit
會(huì)依次執(zhí)行
testXxx()
方法。在
testAbs()
方法中,我們對(duì)
abs()
的測(cè)試分別選擇正數(shù),負(fù)數(shù)和
0
,如果方法返回值與期待結(jié)果相同,則
assertEquals
不會(huì)產(chǎn)生異常。
如果有多個(gè)
testXxx
方法,
JUnit
會(huì)創(chuàng)建多個(gè)
XxxTest
實(shí)例,每次運(yùn)行一個(gè)
testXxx
方法,
setUp()
和
tearDown()
會(huì)在
testXxx
前后被調(diào)用,因此,不要在一個(gè)
testA()
中依賴(lài)
testB()
。
直接運(yùn)行
Run->Run As->JUnit Test
,就可以看到
JUnit
測(cè)試結(jié)果:
綠色表示測(cè)試通過(guò),只要有
1
個(gè)測(cè)試未通過(guò),就會(huì)顯示紅色并列出未通過(guò)測(cè)試的方法。可以試圖改變
abs()
的代碼,故意返回錯(cuò)誤的結(jié)果(比如
return n+1;
),然后再運(yùn)行
JUnit
就會(huì)報(bào)告錯(cuò)誤。
三、在
Spring
中進(jìn)行
DAO
測(cè)試
???
Spring
提供了下列一些特定的JUnit框架擴(kuò)展:
AbstractDependencyInjectionSpringContextTests—
這是一個(gè)針對(duì)所有測(cè)試的超類(lèi),其具體使用依賴(lài)于Spring上下文。
AbstractSpringContextTests—
這是一個(gè)針對(duì)所有的JUnit測(cè)試情形的超類(lèi)。它使用一個(gè)Spring上下文。并且,一般在測(cè)試中不是直接使用它,而是使用AbstractDependencyInjectionSpringContextTests或者AbstractTransactionalSpringContextTests這樣的派生類(lèi)。
AbstractTransactionalSpringContextTests—
這是一個(gè)針對(duì)所有測(cè)試的超類(lèi),我們一般把它應(yīng)用在事務(wù)相關(guān)的測(cè)試中。注意,一旦完成每個(gè)測(cè)試它就會(huì)正常地回滾事務(wù);而且你需要重載onSetUpInTransaction和onTearDownInTransaction方法以便手工開(kāi)始并提交事務(wù)。
AbstractTransactionalDataSourceSpringContextTests—
這是AbstractTransactionalSpringContextTests的一個(gè)子類(lèi),它使用了Spring的基于JDBC的jdbcTemplate工具類(lèi)。
所有上面這些擴(kuò)展將極大程度地簡(jiǎn)化在測(cè)試時(shí)對(duì)于相關(guān)操作的依賴(lài)性注入和事務(wù)管理。
?????? 下面就以一個(gè)用戶(hù) DAO 類(lèi) HibernateUserDao 類(lèi)中的一個(gè)方法 getPasswordByName(String userName) 進(jìn)行測(cè)試作為例子,其中的輸入就是用戶(hù)名,輸出就是用戶(hù)密碼:
測(cè)試類(lèi):
//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
下由于要驅(qū)動(dòng)
Spring
,所以測(cè)試類(lèi)要繼承
AbstractTransactionalDataSourceSpringContextTests
類(lèi),需要實(shí)現(xiàn)一個(gè)方法
String[] getConfigLocations()
,用這個(gè)方法來(lái)獲取
Spring
的配置文件,然后我通過(guò)寫(xiě)
getContext(String[] filePath)
這個(gè)方法來(lái)獲取
Spring
的上下文,在這里我們要獲取待測(cè)試對(duì)象有兩種方法一種就是
setHibernateUserDAO()
和
getHibernateUserDAO()
方法,另外一種就是通過(guò)上下文提取配置文件中定義的
Bean
,然后再獲取具體的方法。
這個(gè)就是測(cè)試結(jié)果: