javascript
详细讲解在Spring中进行集成测试AbstractDependencyInjectionSpringContextTests
http://www.51testing.com/html/06/n-64906-2.html
Spring提供的測試幫助類
??????? Spring在org.springframework.test包中為測試提供了幾個有用的類,它們都是JUnit TestCase的子類。通過層層擴(kuò)展,不斷豐富測試的功能,我們可以通過下圖了解這些類的繼承關(guān)系:?
???
圖 1 Spring測試工具類
??????? 下面,我們來逐個了解這棵承繼類樹中每個節(jié)點(diǎn)測試類的功用,第一個要認(rèn)識的是直接擴(kuò)展于TestCase的ConditionalTestCase測試類。
ConditionalTestCase
??????? 如果你直接通過擴(kuò)展TestCase創(chuàng)建測試用例,則所有帶test前綴的測試方法都會被毫無例外地執(zhí)行。而ConditionalTestCase可以讓你在某些情況下,有選擇地關(guān)閉掉一些測試方法,不讓他們在測試用例中執(zhí)行。這給開發(fā)者帶來了很大的靈活性,因?yàn)樗麄兛梢栽谀炒螠y試中關(guān)閉掉一些測試方法,而僅運(yùn)行當(dāng)前特別關(guān)注的測試方法,將問題域聚集到一定范圍內(nèi)。?
??????? 如果你要關(guān)閉某個測試方法行,僅需實(shí)現(xiàn)ConditionalTestCase的 isDisabledInThisEnvironment(String testMethodName)方法就可以了,ConditionalTestCase在運(yùn)行每一個測試方法前會根據(jù)isDisabledInThisEnvironment()方法判斷是簡單放棄目標(biāo)方法的運(yùn)行,還是按正常方式執(zhí)行之。該方法默認(rèn)情況下對所有的測試方法都返回false,也即執(zhí)行所有的測試方法。讓我們來看一個具體例子:
代碼清單 4 ConditionalTest1:有條件執(zhí)行測試方法 package com.baobaotao.test;
import org.springframework.test.ConditionalTestCase;
public class ConditionalTest1 extends ConditionalTestCase {
①被忽略不執(zhí)行的測試方法
private static String[] IGNORED_METHODS = {"testMethod1","testMethod3"};
@Override
protected boolean isDisabledInThisEnvironment(String testMethodName) {②所有在
for (String method : IGNORED_METHODS) { IGNORED_METHODS數(shù)組中
if (method.equals(testMethodName)) { 的方法都忽略執(zhí)行。
return true;
}
}
return false;
}
public void testMethod1(){ ③不執(zhí)行
System.out.println("method1");
}
public void testMethod2(){ ④執(zhí)行
System.out.println("method2");
}
public void testMethod3(){ ⑤不執(zhí)行
System.out.println("method3");
}
}
??????? 如果我們直接承繼JUnit的TestCase,③、④及⑤處的三個測試方法都會被執(zhí)行,但現(xiàn)在我們通過繼承ConditionalTestCase編寫測試類,并覆蓋了isDisabledInThisEnvironment()方法,當(dāng)測試方法名位于IGNORED_METHODS數(shù)組中時,測試方法就被旁路掉了。因此當(dāng)運(yùn)行ConditionalTest1時,你會發(fā)現(xiàn)只有④處的testMethod2()測試方法得到了執(zhí)行,其它兩個測試方法看起來也被成功執(zhí)行,只不過會程序日志會給出報告,告訴你哪些測試方法是真正被執(zhí)行,而哪些方法被“偽執(zhí)行”的。
ConditionalTestCase其實(shí)可用于任何程序的單元測試中,它本身并沒有和Spring容器有任何關(guān)聯(lián),它僅添加了一個按條件執(zhí)行測試方法的功能。
AbstractSpringContextTests
??????? AbstractSpringContextTests擴(kuò)展于ConditionalTestCase,它維護(hù)了一個static類型的緩存器(HashMap),它使用鍵保存Spring ApplicationContext實(shí)例,這意味著Spring ApplicationContext是JVM級的,不同測試用例、不同測試方法都可以共享這個實(shí)例。也就是說,在運(yùn)行多個測試用例和測試方法時,Spring容器僅需要實(shí)例化一次就可以了,極大地提高了基于Spring容器測試程序的運(yùn)行效率。Spring通過這個測試幫助類解決了前面我們所指出的第1)個問題。
AbstractSingleSpringContextTests
??????? AbstractSingleSpringContextTests繼承于AbstractSpringContextTests,它通過一些方法讓你方便地指定Spring配置文件所在位置:
??????? String[] getConfigLocations():該方法允許你在指定Spring配置文件時使用資源類型前綴,這些資源類型前綴包括:classpath:、file:。以類似于“com/baobaotao/beans.xml”形式指定的資源被當(dāng)成類路徑資源處理;
??????? String[] getConfigPaths():以“/”開頭的地址被當(dāng)成類路徑處理,如“/com/baobaotao/beans.xml”,而未以“/”開頭的地址被當(dāng)成相對于測試類所在包的文件路徑,如“beans.xml”表示配置文件在測試類所在類包的目錄下;?
??????? String getConfigPath():和getConfigPaths()類似,在僅需指定一個配置文件中使用。
??????? 以上三個方法,它們的優(yōu)先級和我們介紹的先后順序?qū)?yīng),也就是說,當(dāng)你在子類中覆蓋了getConfigLocations()方法后,其它兩個方法就沒有意義了。所以你僅需選擇三者當(dāng)中適合的方法進(jìn)行覆蓋,而沒有必要同時覆蓋多個方法。
??????? AbstractSingleSpringContextTests將根據(jù)這些方法指定的Spring配置文件初始化Spring容器,然后將Spring容器引用添加到static緩存中。并通過getApplicationContext()向子類開放ApplicationContext的引用。
??????? 一般情況下,所有的測試類和測試方法都可以共享這個Spring容器直到測試完結(jié),不過在某些極端情況下,測試方法可能會對Spring容器進(jìn)行改動(比如通過程序改變Bean的配置定義),如果這種改變對于其它測試方法來說是有干擾的,這就相當(dāng)于“弄臟”了作為測試現(xiàn)場的Spring容器,因此在下一個測試方法執(zhí)行前必須“抹除”這個改變。你可以簡單地在會“弄臟”Spring容器的測試方法中添加setDirty()方法向AbstractSingleSpringContextTests報告這一行為,這樣在下一個測試方法執(zhí)行前,AbstractSingleSpringContextTests就會重新加載Spring容器以修補(bǔ)被“弄臟”的部分。
??????? 雖然你可以直接繼承AbstractSpringContextTests或AbstractSingleSpringContextTests創(chuàng)建自己的集成測試用例,不過你大可不必如此著急。Spring已經(jīng)提供了幾個功能齊全、實(shí)踐性更強(qiáng)的子類,讓我們繼續(xù)探索Spring集成測試工具類的精彩篇章吧。
?
一般集成測試
??????? 應(yīng)該說,Spring通過AbstractSpringContextTests或AbstractSingleSpringContextTests準(zhǔn)備好了集成測試的一些基礎(chǔ)設(shè)施,在建筑學(xué)上,這叫夯實(shí)地基,而AbstractDependencyInjectionSpringContextTests是在此地基之上建起的第一幢樓房。?
??????? AbstractDependencyInjectionSpringContextTests所新添的主要功能是其子類的屬性能被Spring容器中的Bean自動裝配,你無需手工通過??????? ApplicationContext#getBean()從容器中獲取目標(biāo)Bean自行裝配。它很好回答了前面我們所指出第2)問題,下面我們通過實(shí)例進(jìn)行學(xué)習(xí): 代碼清單 5 DependencyInjectionCtxTest
package com.baobaotao.test;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import com.baobaotao.service.UserService;
public class DependencyInjectionCtxTest
extends AbstractDependencyInjectionSpringContextTests {
private UserService userService;
public void setUserService(UserService userService) {①該屬性設(shè)置方法會被自動調(diào)動
this.userService = userService;
}
@Override
protected String[] getConfigLocations() { ②指定Spring配置文件所在位置
return new String[]{"baobaotao-service.xml","baobaotao-dao.xml"};
}
public void testHasMatchUser(){ ③測試方法
boolean match = userService.hasMatchUser("tom","123456");
assertEquals(true, match);
}
…
}
??????? 在②處,我們指定了Spring配置文件所在的位置,AbstractDependencyInjectionSpringContextTests將使用這些配置文件初始化好Spring容器,并將它們保存于static的緩存中。然后馬上著手根據(jù)類型匹配機(jī)制(byType),自動將Spring容器中匹配測試類屬性的Bean通過Setter注入到測試類中。為了方便說明這一重要的特性,我們先看一下baobaotao-service.xml的內(nèi)容:
<beans>
<tx:annotation-driven/>
①按類型匹配于DependencyInjectionCtxTest的userService屬性
<bean id="userService" class="com.baobaotao.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<property name="loginLogDao" ref="loginLogDao"/>
</bean>
…
</beans>
??????? 根據(jù)baobaotao-service.xml配置文件的內(nèi)容,我們知道Spring容器中有一個UserService Bean,AbstractDependencyInjectionSpringContextTests探測到Spring容器中存在一個匹配于userService屬性的Bean后,就將其注入到DependencyInjectionCtxTest的userService屬性中。userService是這個集成測試類的測試固件,因此我們說AbstractDependencyInjectionSpringContextTests可以自己裝配測試固件。
解決自動裝配問題
??????? 如果Spring容器中擁有多個匹配UserService類型的Bean,由于Spring沒有足夠的信息做出取舍決策,因此會拋出UnsatisfiedDependencyException異常。假設(shè)我們采用以下傳統(tǒng)的事務(wù)管理的配置方式對UserService進(jìn)行配置,按類型匹配的自動裝配機(jī)制就會引發(fā)問題:?
??????? ①用于被代理的目標(biāo)Bean,按類型匹配于UserService <bean id="userServiceTarget" class="com.baobaotao.service.UserServiceImpl">
<property name="userDao" ref="userDao" />
<property name="loginLogDao" ref="loginLogDao"></property>
</bean>
??????? ②通過事務(wù)代理工廠為UserServiceImpl創(chuàng)建的代理Bean,也按匹配于UserService
<bean id="userService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="userServiceTarget" />
<property name="transactionAttributes">
…
</property>
</bean>
??????? 由于①處和②處的Bean都按類型匹配于UserService,在對DependencyInjectionCtxTest的userService屬性進(jìn)行自動裝配將會引發(fā)問題。有兩種針對該問題的解決辦法:
??????? 調(diào)整配置文件,使按類型匹配于UserService的Bean僅有一個,具體有以下兩個方法:
??????? 將①處的Bean作為②處的內(nèi)部Bean進(jìn)行裝配;
??????? 使用基于注解驅(qū)動的事務(wù)管理配置機(jī)制,這樣就無需在配置文件中定義兩個UserService的Bean了。關(guān)于注解驅(qū)動事務(wù)管理配置的詳細(xì)信息,請參見9.6小節(jié)的內(nèi)容。
??????? 改變DependencyInjectionCtxTest的自動裝配機(jī)制:Spring默認(rèn)使用byType類型的自動裝配機(jī)制,但它允許你通過setAutowireMode()的方法改變默認(rèn)自動裝配的機(jī)制,比如你可以調(diào)用setAutowireMode(AUTOWIRE_BY_NAME)方法啟用按名稱匹配的自動裝配機(jī)制。AbstractDependencyInjectionSpringContextTests定義了三個代表自動裝配機(jī)制類型的常量,分別說明如下:
? AUTOWIRE_BY_TYPE:按類型匹配的方式進(jìn)行自動裝配,這個默認(rèn)的機(jī)制;
? AUTOWIRE_BY_NAME:按名字匹配的方式進(jìn)行自動裝配
? AUTOWIRE_NO:不使用自動裝配機(jī)制,這意味著你需要手工調(diào)用getBean()進(jìn)行裝配。
??????? 現(xiàn)在我們解決了在自動裝配時,因Spring容器中存在多個匹配Bean而導(dǎo)致的問題,接下來讓我們考察另一個自動裝配的問題。
?
?
依賴檢查
??????? 假設(shè)我們在DependencyInjectionCtxTest添加一個User類型的屬性并提供Setter方法,而Spring容器中沒有匹配該屬性的Bean:
package com.baobaotao.test;
…
import com.baobaotao.domain.User;
public class DependencyInjectionCtxTest extends AbstractDependencyInjectionSpringContextTests {
private User user;
public void setUser(User user) {
this.user = user;
}
…
}
??????? 猜想一下重新運(yùn)行DependencyInjectionCtxTest將會發(fā)生什么情況呢?答案可能讓你失望:UnsatisfiedDependencyException再次象黑幕一樣降臨。在默認(rèn)情況下, AbstractDependencyInjectionSpringContextTests要求所有屬性都能在Spring容器中找到對應(yīng)Bean,否則拋出異常。
??????? 仔細(xì)思考一下,這種運(yùn)行機(jī)制并非沒有道理,因?yàn)榧热荒阋呀?jīng)提供了Setter方法,就相當(dāng)于給出了這樣的暗示信息:“這個屬性測試類自身創(chuàng)建不了,必須由外部提供”。而在使用自動裝配機(jī)制的情況下,測試類屬性自動從Spring容器中注入匹配的屬性,一般情況下不會手工去調(diào)用Setter方法準(zhǔn)備屬性。
??????? 如果你出于一些特殊的理由,希望在采用自動裝配的情況下,如果有屬性未得到裝配也不在乎,那么你可以在測試類構(gòu)造函數(shù)中調(diào)用setDependencyCheck(false)方法達(dá)到目的:
package com.baobaotao.test;
…
public class DependencyInjectionCtxTest extends AbstractDependencyInjectionSpringContextTests {
public DependencyInjectionCtxTest(){
setDependencyCheck(false); ①告知不進(jìn)行屬性依賴性檢查
}
…
}
??????? 這個AbstractDependencyInjectionSpringContextTests就不會對測試類有些屬性找不到匹配Bean而拋出異常了。
??????? 在不提供Setter方法的情況下自動注入
??????? 大多數(shù)IDE都提供了為屬性變量自動生成Setter方法的操作,因此客觀地說,為屬性編寫一個Setter方法的工作根本不值一提。如果你覺得眾多的Setter方法影響了視覺感觀,但又希望享受測試類屬性自動裝配的好處,Spring也不會讓你失望的。你需要做的是以下兩步的工作:?
??????? 1) 將需要自動裝配的屬性變量聲明為protected;?
??????? 2) 在測試類構(gòu)造函數(shù)中調(diào)用setPopulateProtectedVariables(true)方法。 package com.baobaotao.test;
…
public class DependencyInjectionCtxTest extends AbstractDependencyInjectionSpringContextTests {
protected UserService userService; ①將屬性聲明為protected
// public void setUserService(UserService userService) { ②大膽將Setter方法移除掉
// this.userService = userService;
// }
public DependencyInjectionCtxTest(){
setDependencyCheck(false);
setPopulateProtectedVariables(true); ③啟用直接對屬性變量進(jìn)行注釋的機(jī)制
}
…
}
??????? 將屬性聲明為protected后并通過setPopulateProtectedVariables(true)啟用對屬性變量直接注入的機(jī)制(啟用反射機(jī)制注入),你就可以避免為屬性變量編寫對應(yīng)的Setter方法了。
??????? 提示 屬性如果聲明為public,雖然你也調(diào)用了setPopulateProtectedVariables(true)方法,屬性變量依然不會被自動注入。所以這種機(jī)制僅限于protected的屬性變量。
方便地恢復(fù)測試數(shù)據(jù)庫現(xiàn)場
??????? 我們現(xiàn)在已經(jīng)可以通過AbstractDependencyInjectionSpringContextTests的屬性自動裝配機(jī)制方便地建立起測試固件,省卻手工調(diào)用getBean()自行準(zhǔn)備測試固件的煩惱。當(dāng)我們對UserService的hasMatchUser()和findUserByUserName()方法進(jìn)行測試時,不會有任何問題,因?yàn)檫@兩個方法僅對數(shù)據(jù)庫執(zhí)行讀操作。但UserService以下兩個接口方法會對數(shù)據(jù)庫執(zhí)行更改操作:
void loginSuccess(User user);
void registerUser(User user);
??????? 當(dāng)我們對這兩個接口方法進(jìn)行測試時,它們將會在數(shù)據(jù)庫中產(chǎn)生持久化數(shù)據(jù)。考慮對registerUser(User user)方法進(jìn)行測試時,我們可能編寫如下所示的測試方法:
public void testRegisterUser(){
User user = new User();
user.setUserId(2);
user.setUserName("john");
user.setPassword("123456");
userService.registerUser(user);
}
??????? 當(dāng)?shù)谝淮纬晒\(yùn)行testRegisterUser()測試方法時,將在數(shù)據(jù)庫中產(chǎn)生一條主鍵為2的記錄,如何第二次重新運(yùn)行testRegisterUser()測試方法其結(jié)果將不言自明:因主鍵沖突導(dǎo)致測試方法執(zhí)行失敗,最終報告測試用例沒有通過。在這種情況下,測試用例未通過并不是因?yàn)閁serServiceImpl#registerUser(User user)存在邏輯錯誤,而是因?yàn)闇y試方法的積累效應(yīng)導(dǎo)致外在設(shè)施的現(xiàn)場發(fā)生變化而引起的問題。
??????? 為了防止這種問題,測試用例必須在保證不對數(shù)據(jù)庫狀態(tài)產(chǎn)生持久化變化的情況下,對目標(biāo)類的數(shù)據(jù)操作邏輯正確性進(jìn)行檢測。乍一聽這一要求有點(diǎn)貌似于“既想馬兒跑,又想馬兒不吃草”一樣充滿悖論,實(shí)則不然。只要我們讓測試方法不提交事務(wù),在測試完后自動回滾事務(wù),就皆大歡喜了。
?
讓測試方法自動擁有回滾能力
??????? AbstractTransactionalSpringContextTests專為解決以上問題而生,也就是說前面我們所提及的第3)個問題在此得到了回答。只要繼承該類創(chuàng)建測試用例,在默認(rèn)情況下,測試方法中所包含的事務(wù)性數(shù)據(jù)操作都會在測試方法返回前被回滾。由于事務(wù)回滾操作發(fā)生在測試方法返回前的點(diǎn)上,所以你可以象往常一樣在測試方法體中對數(shù)據(jù)操作的正確性進(jìn)行校驗(yàn)。 代碼清單 6 UserServiceIntegrateTest:
package com.baobaotao.service;
import org.springframework.test.AbstractTransactionalSpringContextTests;
import com.baobaotao.domain.User;
public class UserServiceIntegrateTest extends AbstractTransactionalSpringContextTests {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
protected String[] getConfigLocations() {
return new String[]{"baobaotao-service.xml", "baobaotao-dao.xml"};
}
public void testRegisterUser(){ ①測試方法中的數(shù)據(jù)操作將在方法返回前被回滾,不會對數(shù)據(jù)庫
User user = new User(); 產(chǎn)生永久性數(shù)據(jù)操作,第二次運(yùn)行該測試方法時,依舊可以
user.setUserId(2); 成功運(yùn)行。
user.setUserName("john");
user.setPassword("123456");
userService.registerUser(user);
User user1 = userService.findUserByUserName("john"); ②對數(shù)據(jù)操作進(jìn)行
assertEquals(user.getUserId(), user1.getUserId()); 正確性檢驗(yàn)
}
}
??????? 如果testRegisterUser()是直接繼承于AbstractDependencyInjectionSpringContextTests類的測試方法,則重復(fù)運(yùn)行該測試方法就會發(fā)生數(shù)據(jù)沖突問題。但因?yàn)樗挥诶^承于AbstractTransactionalSpringContextTests的測試用例類中,測試方法中對數(shù)據(jù)庫的操作會被正確回滾,所以重復(fù)運(yùn)行不會有任何問題。
??????? 如果你確實(shí)希望測試方法中對數(shù)據(jù)庫的操作持久生效而不是被回滾,Spring也可以滿足你的要求,你僅需要在測試方法中添加setComplete()方法就可以了。
public void testRegisterUser(){
…
User user1 = userService.findUserByUserName("john");
assertEquals(user.getUserId(), user1.getUserId());
setComplete(); ①測試方法中的事務(wù)性數(shù)據(jù)操作將被提交
}
AbstractTransactionalSpringContextTests還擁有幾個可用于初始化測試數(shù)據(jù)庫,并在測試完成后清除測試數(shù)據(jù)的方法,分別介紹如下:
? onSetUpBeforeTransaction()/onTearDownAfterTransaction():子類可以覆蓋這兩個方法,以便在事務(wù)性測試方法運(yùn)行的前后執(zhí)行一些數(shù)據(jù)庫初始化的操作并在事務(wù)完成后清除之;
? onSetUpInTransaction()/onTearDownInTransaction():這對方法和前面介紹的方法完成相同的功能,只不過它們是在測試方法的相同事務(wù)中執(zhí)行的。
??????? AbstractTransactionalSpringContextTests另外還提供了一組用于測試延遲數(shù)據(jù)加載的方法:endTransaction()/startNewTransaction()。我在測試Hibernate、JPA等允許延遲數(shù)據(jù)加載的應(yīng)用時,如何模擬數(shù)據(jù)在Service層事務(wù)中被部分加載,當(dāng)傳遞到Web層時重新打開事務(wù)完成延遲部分?jǐn)?shù)據(jù)加載的測試場景呢?這兩個方法即為此用途而生:你可以在測試方法中顯式調(diào)用endTransaction()方法以模擬從Service層中獲取部分?jǐn)?shù)據(jù)后返回,爾后,再通過startNewTransaction()開啟一個和原事務(wù)無關(guān)新事務(wù)——模擬在Web層中重新打開事務(wù),接下來你就可以訪問延遲加載的數(shù)據(jù),看是否一切如期所料了。
??????? 在代碼清單 6的②處,我們通過UserService#findUserByUserName()方法對前面registerUser(user)方法數(shù)據(jù)操作的正確性進(jìn)行檢驗(yàn)。應(yīng)該說,我們非常幸運(yùn),因?yàn)樵赨serService中剛好存在一個可用于檢測registerUser(user)數(shù)據(jù)操作正確性的方法。讓我們考慮另外的一種情況:要是 UserService不存在這樣的方法,我們該如何檢測registerUser(user)數(shù)據(jù)操作結(jié)果的正確性呢?顯然我們不能使用肉眼觀察的方法,那難道為了驗(yàn)證數(shù)據(jù)操作正確性專門編寫一個配合性的數(shù)據(jù)訪問類不成?
通過JDBC訪問數(shù)據(jù)庫,檢測數(shù)據(jù)操作正確性
??????? 正當(dāng)我們“山重水復(fù)疑無路”的時候,讓我們再往前走上一程,柳暗花明將倏忽而至
——AbstractTransactionalDataSourceSpringContextTests就是花開景明之所。該類繼承于AbstractTransactionalSpringContextTests,它添加了一個JdbcTemplate,你可以借由此道快意直達(dá)數(shù)據(jù)庫。它自動使用Spring容器中的數(shù)據(jù)源(DataSource)創(chuàng)建好一個JdbcTemplate實(shí)例并開放給子類使用。值得注意的是,如果你采用byName自動裝配機(jī)制,數(shù)據(jù)源Bean的名稱必須取名為“dataSource”。
??????? 讓我們對UserServiceIntegrateTest進(jìn)行改造,以便讓其自動擁有訪問數(shù)據(jù)庫的設(shè)施(JdbcTemplate),并用靈活的方法訪問數(shù)據(jù)庫進(jìn)行數(shù)據(jù)操作的檢驗(yàn),其代碼如下所示:
代碼清單 7 UserServiceIntegrateWithJdbcTest
package com.baobaotao.service;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
…
public class UserServiceIntegrateWithJdbcTest
extends AbstractTransactionalDataSourceSpringContextTests {①注意:繼承類發(fā)生調(diào)整
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
protected String[] getConfigLocations() {
return new String[]{"baobaotao-service.xml", "baobaotao-dao.xml"};
}
public void testRegisterUser(){
User user = new User();
user.setUserId(2);
user.setUserName("john");
user.setPassword("123456");
userService.registerUser(user);
String sqlStr = " SELECT user_id FROM t_user WHERE user_name ='john' ";
int userId = jdbcTemplate.queryForInt(sqlStr); ①可以直接使用JdbcTemplate訪問數(shù)據(jù)庫了
assertEquals(user.getUserId(), userId);
setComplete();
}
}
??????? jdbcTemplate是AbstractTransactionalDataSourceSpringContextTests類中定義的,子類可以直接使用它訪問數(shù)據(jù)庫。這樣我們就可以靈活地訪問數(shù)據(jù)庫以檢驗(yàn)?zāi)繕?biāo)測試方法的數(shù)據(jù)操作正確性。至此,我們終于畢其功于一役于AbstractTransactionalDataSourceSpringContextTests,順利解決前面我們中指出的最后問題。
??????? 只要你通過擴(kuò)展AbstractTransactionalSpringContextTests及其子類創(chuàng)建測試用例,所有測試方法都會工作了事務(wù)環(huán)境下。也就是說,即使某些測試方法不需要訪問數(shù)據(jù)庫,也會產(chǎn)生額外的事務(wù)管理開銷,是否可以對測試方法啟用事務(wù)管理的行為進(jìn)行控制呢?此外,在一些情況下,除對目標(biāo)方法邏輯運(yùn)行的正確性進(jìn)行檢驗(yàn)外,我們還希望對目標(biāo)方法的運(yùn)行性能進(jìn)行測試:如當(dāng)目標(biāo)方法運(yùn)行時間超過200毫秒時,則測試用例視為未通過。諸如此類的問題,我們目前學(xué)習(xí)到的知識還不能很好的應(yīng)付。Spring 2.0新增了注解驅(qū)動的測試工具為我們指明了道路,你僅需要通過簡單為測試方法標(biāo)注注解,我們剛才提出的“疑難”問題就可以迎刃而解了。
小結(jié)
??????? 本文我們講述了使用Spring提供的一套測試工具對Spring應(yīng)用程序進(jìn)行集成測試所需的所有知識。?
??????? Spring建議你不應(yīng)該在單元測試時使用到Spring容器,你應(yīng)該在集成測試時才使用到Spring容器。手工創(chuàng)建測試固件或者手工裝配測試固件的工作都是單調(diào)乏味沒有創(chuàng)意的工作,通過使用Spring為集成測試提供了幫助類,你就可以享受測試固件自動裝配的好處,將精力集中到目標(biāo)類邏輯測試編寫的工作上。
??????? 應(yīng)該說大部分的Java應(yīng)用都是Web應(yīng)用,而大部分的Java Web應(yīng)用都是數(shù)據(jù)庫相關(guān)的應(yīng)用,對數(shù)據(jù)庫應(yīng)用進(jìn)行測試經(jīng)常要考慮數(shù)據(jù)準(zhǔn)備、數(shù)據(jù)庫現(xiàn)場恢復(fù)、靈活訪問數(shù)據(jù)以驗(yàn)證數(shù)據(jù)操作正確性等等的問題。這些問題如果沒有一個很好的支持工具,將給編寫測試用例造成挑戰(zhàn),幸好Spring都為我們搭建好滿足這些需求的測試平臺,你僅需要在此基礎(chǔ)上編寫特定的測試用例就可以了。
?
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的详细讲解在Spring中进行集成测试AbstractDependencyInjectionSpringContextTests的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: get pid and kill
- 下一篇: 兼容Tomcat和Weblogic的Sp