引述:程序測試對保障應用程序正確 性而言,其重要性怎麼樣強調都不爲過。JUnit是必須事先掌握的測試框架,大多數測試框架和測試工具都在此基礎上擴展而來,Spring對測試所提供的 幫助類也是在JUnit的基礎上進行演化的。直接使用JUnit測試基於Spring的應用存在諸多不便,不可避免地須要將大量的精力用於應付測試夾具準 備、測試現場恢復、訪問測試數據操做結果等邊緣性的工做中。Mockito、Unitils、Dbunit等框架的出現,這些問題有了很好的解決方案,特 別是Unitils結合Dbunit對測試DAO層提供了強大的支持,大大提升了編寫測試用例的效率和質量。
Unitils海納百川(Junit,dbunit,mockito spring hibernate and so on..),以打造一個在實際應用開發中真正實戰的測試框架,是致力於應用實戰的開發者不得不學習的開源框架。
Unitils概述
Unitils測試框架目的是讓單元測試變得更加容易和可維護。Unitils構建在DbUnit與EasyMock項目之上並與JUnit和 TestNG相結合。支持數據庫測試,支持利用Mock對象進行測試並提供與Spring和Hibernate相集成。Unitils設計成以一種高度可 配置和鬆散耦合的方式來添加這些服務到單元測試中,目前其最新版本是3.1。
Unitils功能特色
java
Unitils模塊組件
Unitils經過模塊化的方式來組織各個功能模塊,採用相似於Spring的模塊劃分方式,如unitils-core、unitils-database、unitils-mock等。比之前整合在一個工程裏面顯得更加清晰,目前全部模塊以下所示:spring
Unitils的核心架構中包含Moudule和TestListener兩個概念,相似Spring中黏連其餘開源軟件中的FactoryBean概念。能夠當作第三方測試工具的一個黏合劑。總體框架如圖16-4所示:
經過TestListener能夠在測試運行的不一樣階段注入某些功能。同時某一個TestListener又被一個對應的Module所持有。 Unitils也能夠當作一個插件體系結構,TestListener在整個Unitils中又充當了插件中擴展點的角色,從TestListener這 個接口中咱們能夠看到,它能夠在crateTestObject、before(after)Class、 before(after)TestMethod、beforeSetup、afterTeardown的不一樣切入點添加不一樣的動做。
Unitils配置文件 sql
Unitils的配置定義了通常配置文件的名字unitils.properties和用戶自定義配置文件unitils- local.properties,並給出了默認的模塊及模塊對應的className,便於Unitils加載對應的模塊module。可是若是用戶分 別在unitils.properties文件及unitils -local.properties文件中對相同屬性配置不一樣值時,將會以unitils-local.properties 的配置內容爲主。
Unitils斷言
典型的單元測試通常都包含一個重要的組成部分:對比實際產生的結果和但願的結果是否一致的方法,即斷言方法(assertEquals)。Unitils 爲咱們提供了一個很是實用的斷言方法,咱們以第2章中編寫的用戶領域對象User爲藍本,比較兩個User對象的實例來開始認識Unitils的斷言之 旅。
assertReflectionEquals:反射斷言
在Java世界中,要比較現有兩個對象實例是否相等,若是類沒有重寫equals()方法,用兩個對象的引用是否一致做爲判斷依據。有時候,咱們並不須要 關注兩個對象是否引用同一個對象,只要兩個對象的屬性值同樣就能夠了。在JUnit單元測試中,有兩種測試方式進行這樣的場景測試:一是在比較實體類中重 寫equals()方法,而後進行對象比較;二是把對象實例的屬性一個一個進行比較。無論採用哪一種方法,都比較煩鎖,Unitils爲咱們提供了一種很是 簡單的方法,即便用ReflectionAssert.assertReflectionEquals方法, 如代碼清單16-11所示: 數據庫
ReflectionAssert. AssertReflectionEquals(指望值,實際值,比較級別)方法爲咱們提供了各類級別的比較斷言。下面咱們依次介紹這些級別的比較斷言。
ReflectionComparatorMode.LENIENT_ORDER:忽略要斷言集合collection 或者array 中元素的順序。
ReflectionComparatorMode.IGNORE_DEFAULTS:忽略Java類型默認值,如引用類型爲null,整型類型爲0,或者布爾類型爲false時,那麼斷言忽略這些值的比較。
ReflectionComparatorMode.LENIENT_DATES:比較兩個實例的Date是否是都被設置了值或者都爲null,而忽略Date的值是否相等。
assertLenientEquals:斷言
ReflectionAssert 類爲咱們提供了兩種比較斷言:既忽略順序又忽略默認值的斷言assertLenientEquals,使用這種斷言就能夠進行簡單比較。下面經過實例學習其具體的用法,如代碼清單16-12所示。數組
assertPropertyXxxEquals:屬性斷言
assertLenientEquals 和assertReflectionEquals 這兩個方法是把對象做爲總體進行比較,ReflectionAssert 類還給咱們提供了只比較對象特定屬性的方法:assertPropertyReflection Equals()和assertPropertyLenientEquals()。下面經過實例學習其具體的用法,如代碼清單16-13所示。 session
assertPropertyReflectionEquals()斷言是默認嚴格比較模式可是能夠手動設置比較級別的斷言,assertPropertyLenientEquals()斷言是具備忽略順序和忽略默認值的斷言。
集成Spring
Unitils 提供了一些在Spring 框架下進行單元測試的特性。Spring 的一個基本特性就是,類要設計成爲沒有Spring 容器或者在其餘容器下仍然易於進行單元測試。可是不少時候在Spring 容器下進行測試仍是很是有用的。
Unitils 提供瞭如下支持 Spring 的特性:架構
ApplicationContext 配置
能夠簡單地在一個類、方法或者屬性上加上@SpringApplicationContext 註解,並用Spring的配置文件做爲參數,來加載Spring應用程序上下文。下面咱們經過實例來介紹一下如何建立ApplicationContext。 app
在①-1處,經過@SpringApplicationContext 註解加載baobaotao-service.xml和baobaotao- dao.xml兩個配置文件,生成一個Spring應用上下文,咱們就能夠在註解的範圍內引用applicationContext這個上下文。在①-2 處,經過@SpringBean註解注入當前Spring容器中相應的Bean,如實例中加載ID爲「userService」的Bean到當前測試範 圍。在①-3處,經過JUnit斷言驗證是否成功加載applicationContext和userService。Unitils加載Spring上 下文的過程是:首先掃描父類的@SpringApplicationContext註解,若是找到了就在加載子類的配置文件以前加載父類的配置文件,這樣 就可讓子類重寫配置文件和加載特定配置文件。
細心的讀者可能會發現,採用這種方式加載Spring應用上下文,每次執行測試時,都會重複加載Spring應用上下文。Unitils爲咱們提供在類上加載Spring應用上下文的能力,以免重複加載的問題。 框架
在父類BaseServiceTest裏指定了Spring配置文件,Spring應用上下文只會建立一次,而後在子類 SimpleUserServiceTest 裏會重用這個應用程序上下文。加載Spring應用上下文是一個很是繁重的操做,若是重用這個Spring應用上下文就會大大提高測試的性能。dom
在①處,使用@SpringBean 註解從Spring容器中加載一個ID爲userService的Bean。在②處,使用@ SpringBeanByType註解從Spring容器中加載一個與UserService相同類型的Bean,若是找不到相同類型的Bean,就會拋 出異常。在③處,使用@SpringBeanByName 註解從Spring容器中加載一個與當前屬性名稱相同的Bean。
集成Hibernate
Hibernate是一個優秀的O / R開源框架,它極大地簡化了應用程序的數據訪問層開發。雖然咱們在使用一個優秀的O/R框架,但並不意味咱們無須對數據訪問層進行單元測試。單元測試仍然 很是重要。它不只能夠確保Hibernate映射類的映射正確性,也能夠很便捷地測試HQL查詢等語句。Unitils爲方便測試 Hibernate,提供了許多實用的工具類,如HibernateUnitils就是其中一個,使用 assertMappingWithDatabaseConsistent()方法,就能夠方便測試映射文件的正確性。
SessionFactory 配置
能夠簡單地在一個類、方法或者屬性上加上@ HibernateSessionFactory 註解,並用Hibernate的配置文件做爲參數,來加載Hibernate上下文。下面咱們經過實例來介紹一下如何建立SessionFactory。
在父類BaseDaoTest裏指定了Hibernate配置文件,Hibernate應用上下文只會建立一次,而後在子類 SimpleUserDaoTest裏會重用這個應用程序上下文。加載Hibernate應用上下文是一個很是繁重的操做,若是重用這個 Hibernate應用上下文就會大大提高測試的性能。
爲了更好演示如何應用Unitils測試基於Hibernate數據訪問層,在這個實例中不使用Spring框架。因此在執行測試時,須要先建立相應的數 據訪問層實例,如實例中的userDao。其建立過程如①處所示,先手工實例化一個UserDao,而後獲取父類中建立的SessionFactory, 並設置到UserDao中。在②處,使用Unitils提供的工具類HibernateUnitils中的方法測試咱們的Hibernate映射文件。在 ③處,經過JUnit的斷言驗證 UserDao相關方法,看是否與咱們預期的結果一致。
集成Dbunit
Dbunit是一個基於JUnit擴展的數據庫測試框架。它提供了大量的類,對數據庫相關的操做進行了抽象和封裝。Dbunit經過使用用戶自定義的數據 集以及相關操做使數據庫處於一種可知的狀態,從而使得測試自動化、可重複和相對獨立。雖然不用Dbunit也能夠達到這種目的,可是咱們必須爲此付出代價 (編寫大量代碼、測試及維護)。既然有了這麼優秀的開源框架,咱們又何須再造輪子。目前其最新的版本是2.4.8。
隨着Unitils的出現,將Spring、Hibernate、DbUnit等整合在一塊兒,使得DAO層的單元測試變得很是容易。Unitils採用模 塊化方式來整合第三方框架,經過實現擴展模塊接口org.unitils.core.Module來實現擴展功能。在Unitils中已經實現一個 DbUnitModule,很好整合了DbUnit。經過這個擴展模塊,就能夠在Unitils中使用Dbunit強大的數據集功能,如用於準備數據的 @DataSet註解、用於驗證數據的@ExpectedDataSet註解。Unitils集成DbUnit流程圖如圖16-5所示。
16.4.5 自定義擴展模塊
Unitils經過模塊化的方式來組織各個功能模塊,對外提供一個統一的擴展模塊接口org.unitils.core.Module來實現與第三方框架 的集成及自定義擴展。在Unitils中已經實現目前一些主流框架的模塊擴展,如Spring、Hibernate、DbUnit、Testng等。若是 這些內置的擴展模塊沒法知足需求,咱們能夠實現本身的一些擴展模塊。擴展Unitils模塊很簡單,如代碼清單16-19所示。
在①處新建自定義擴展模塊CustomExtModule,實現Module接口。在②處新建自定義監聽模塊,繼承TestListener。在 ③處重寫(@Override)TestListener裏的相關方法,完成相關擴展的功能。實現自定義擴展模塊以後,剩下的工做就是在Unitils配 置文件unitils.properties中註冊這個自定義擴展的模塊:
http://stamen.iteye.com/blog/1480316