一個suite(套件) 由一個或多個測試組成。 一個test(測試) 由一個或多個類組成 一個class(類) 由一個或多個方法組成。
@BeforeSuite/@AfterSuite 在某個測試套件開始以前/在某個套件全部測試方法執行以後
@BeforeTest/@AfterTest 在某個測試開始以前/在某個測試全部測試方法執行以後
@BeforeClass/@AfterClass 在某個測試類開始以前/在某個類的全部測試方法執行以後
@BeforeMethod/@AfterMethod 在某個測試方法以前/在某個測試方法執行以後
@BeforeGroup/@AfterGroup 在某個組的全部測試方法以前/在某個組的全部測試方法執行以後
測試的一個目標就是確保代碼按照預期的方式工做。這種測試要麼在用戶層面上進行,要麼在編程層面上進行。這兩種類型的測試分別是經過功能測試和單元測試來實現的。
針對失敗而測試
Java提供了兩種不一樣類型的異常:從java.lang.RuntimeException派生的運行時刻異常和從java.lang.Exception派生的被檢查的異常。
拋出被檢查的異常的經驗法則:調用者能夠爲這個異常作什麼嗎?若是答案是確定的,那麼可能應該是用被檢查的異常,不然,最好是選擇運行時刻異常。
屬性expectedExceptions是一組類,包含了這個測試方法中預期會拋出的異常列表。若是沒有拋出異常,或拋出的異常再也不該屬性的類表中,那麼TestNG就會認爲這個測試方法失敗了。
單一職責:
testng-failed.xml
當您執行包涵失敗的測試套件時,TestNG會在輸出目錄(默認是test-output/)下自動生成一個名爲testng-failded.xml的問他件。這個XML文件包含了原來的testng.xml中失敗的方法所構成的子集。
TestNG讓您能夠選擇本身將測試類實例化。這是經過@Factory annotation來實現的,他必須放在返回一個對象數組方法的頂部。全部這些對象都必須是包含TestNG annotation的類的實例。若是有@Factory annotation,那麼這個循環會繼續下去,知道TestNG拿到的都是沒有@Factory annotation實例,或者@Factory方法都已被調用過的實例。
能夠安全的在同一個類包含@Factory和@Test annotation,由於TestNG確保@Factory方法只被調用一次。
org.testng.ITest接口
當TestNG遇到實現了這個接口的測試類時,他會在生成各類報告中包含getTestName()方法返回的信息。
數據驅動測試
測試須要針對許多具備相似結構的數據來執行。 實際的測試邏輯是同樣的,僅僅發生改變的是數據。 數據能夠被一組不一樣的人修改。
參數測試方法 測試邏輯能夠很是簡單或不易改變,而提供給他的數據確定會隨着時間增加。
TestNG能夠經過兩種方式向測試方法傳遞參數:
一、利用testng.xml傳遞參數
在測試方法中指定參數
若是犯下如下錯誤之一,TestNG將拋出一個異常:
2.利用@DataProvider傳遞參數
若是須要向測試方法傳遞的參數不是基本的Java類型,或者若是須要的值智能在運行時刻建立,那麼咱們應該考慮使用@DataProvider annotation。
數據提供者是用@Dataprovider標註的方法。這個annotation只有一個字符串屬性:他的名稱,若是沒有提供名稱,數據提供者的名稱就默認採用方法的名稱。
數據提供者同時實現兩個目的:
向測試方法傳遞任意數目的參數 根據須要,容許利用不一樣的參數集合對他的測試方法進行屢次調用。
因爲數據提供者是測試類中的一個方法,他能夠屬於一個超類,而後被一些測試方法複用。咱們也能夠有幾個數據提供者,只要他們定義在測試類或者他的一個子類上。當咱們像在合適的地方記錄數據源,並在幾個測試方法中複用他時,這種方法是很方邊的。
針對數據提供者的參數 數據提供者自己能夠接受兩個類型的參數:Method和ITestContext
Method參數 若是數據提供者的第一個參數是java.lang.reflect.Method,TestNG傳遞這個將調用的測試方法。若是您但願數據提供者根據不一樣的測試方法返回不一樣的數據,那麼這種作法就很是有用。
使用同一個數據提供者的地方:
數據提供者代碼至關複雜,應該保存在一個地方,這樣維護起來更方便。 咱們要傳入數據的那些測試方法具備許多參數,其中只有少數參數是不同的。 咱們引入了某個方法的特殊狀況。
ITestContext參數 若是一個數據提供者在方法簽名中聲名了一個ITestContext類型的參數,TestNG就會將當前的測試上下文設置給它,這使得數據提供者可以知道當前測試執行的運行時刻參數。
ITestContext對象中的數據是運行時刻的信息,不是靜態的信息:這個測試方法即屬於unit-test組,也屬於functional-test組,但在運行時刻,咱們決定只執行functional-test組,這個值由ITestContext#getIncludeGroups方法返回。
延遲數據提供者
爲了實現這種方法,TestNG容許咱們從數據提供者返回一個Iterator,而不是一個二維對象數組。
這種方法與數組不一樣之處在於,當TestNG須要從數據提供者取得下一組參數時,他會調用Iterator的next方法,這樣就有機會在最後一刻實例化相應的對象,即恰好在須要這些參數的測試方法被調用以前。
若是傳遞的參數是簡單類型的常數,利用testng.xml的方法是很好的。檔咱們須要更多靈活性,並知道參數的數目和值將隨時間增長時,咱們可能應該選擇@DataProvider。
提供數據 數據的位置多是:硬編碼在Java源碼中、再文本文件中、在屬性文件中、在Excel表格中、在數據庫中、在網絡中…。
數據提供者仍是工廠 數據提供者向測試方法傳遞參數,而工廠像構造方法傳遞參數。
不如不能肯定使用哪一種方法,那麼就看看測試方法所使用的參數。是否有幾個測試方法須要接收一樣的參數?若是是這樣,您可能最好是將這些參數保存在一個字段中,而後在幾個方法中複用這個字段,這就意味着最好是選擇工廠。反之,若是全部的測試方法都須要傳入不一樣的參數,那麼數據提供者多是最好的選擇。
異步測試 異步代碼一般出如今下列領域:
測試異步代碼比測試同步代碼的問題更多:
當調用異步時有三種可能的結果:
測試異步代碼也一樣遵循下面的模式:
發出異步調用,他會當即返回。若是可能,制定一個回調對象。
若是有回調方法:
等待結果,在接到結果是設置布爾變量,反應結果是不是您的預期。
在測試方法中,監視那個布爾變量,等到他被設置或過了一段時間。
若是沒有回調方法:
在測試方法中,按期檢查預期的值。若是過了一段時間尚未檢查到預期值,就失敗並退出。
不指定回調方法
在這個測試中,消息是做爲測試初始化的一部分,利用@BeforeClass發出的,這保證了這段代碼在測試方法調用以前執行而且只執行一次。在初始化後TestNG將調用waitForAswer測試方法,他將進行不徹底忙等。
有回調方法:
如今sendMessage()是一個@Test方法,他將包含在最終的報告中,若是發送消息失敗,TestNG將跳過waitForAnswer測試方法,並把他表示爲SKIP。
TestNG調用該方法100次,若是98%的調用成功,就認爲整體測試經過。
測試多線程代碼 併發測試
@invocationCount至關簡單,在不考慮併發時也可使用:他決定了TestNG調用一個測試方法的次數。
@threadPoolSize要求TestNG分配必定數量的線程,並使用這些線程來調用這個測試方法,當一個測試完成以後,執行他的線程將歸還給線程池,而後能夠用於下一次調用。
併發執行
thread-count屬性指定了線程數目,TestNG將使用這些線程來執行這個測試套件中的全部測試方法,parallel屬性告訴TestNG您在執行這些測試時但願採用的並行模式。
arallel=」methods」 在這種模式下,每一個測試方法將在他本身的一個線程中執行。
arallel=」test」 在這種模式下,在某個標籤內的全部測試方法將在他們本身的一個線程中執行。
在tests模式中,TestNG保證每一個將在他本身的線程中執行。若是但願測試不安全的代碼,這一點是很是重要的。在method模式中,全部限制都被取消,沒法預測哪些方法將在同一個線程中執行,哪些方法將在不一樣的測試中執行。
爲可模擬性設計 爲了可以成功地使用模擬模擬對象或樁,重要得失要確保代碼的設計能讓使用模擬對象或樁變得簡單而直接。 這種設計最重要的方面就是正確的肯定組件之間的交互,從而肯定組件的交互接口。
若是咱們有2個組件A和B,A須要用到B,那麼應該經過B的接口來完成,而不是經過B的具體實現。
Singleton查找
對於某個對象智能由一個實例,這在項目生命週期的後期產生阻礙效果。
JNDI定位服務
不可以向A提供一個受控制的B的實例。只有一個全局實例,A只能取得這個實例。
依賴注入
從外部通知A應該使用哪一個B的實例。這讓咱們可以根據實際狀況靈活地決定向A提供B的哪一個實例。
EasyMock
1建立模擬對象 這是經過createMock方法完成的,傳入但願模擬的類做爲參數。
2紀錄預期行爲 只要在模擬對象上調用咱們預期會被調用的方法,就能紀錄預期的行爲。當用到某些具體的參數時,只要將這些參數傳入就能夠了。
3調用主要被測對象 在主要的被測對象上調用一個方法或一組方法,預期此次調用將倒置被測對象調用模擬對象的那些預期的方法。
4驗證預期行爲 最後調用verify,檢查全部的模擬對象。
JMock jMock是一個模擬庫,她讓咱們經過編成的方式來之行約束條件。
選擇正確的策略
缺乏接口 有時候,咱們面對的是龐大臃腫的遺留系統,沒有向指望的那樣有很好的設計。 大多數模擬庫如今都容許替換類,而不只是接口。這些庫會在運行時刻生成一個新類,經過字節碼操做來實現指定的契約。
複雜的類 若是咱們獲得了一些類,他們擁有20多個方法,與許多其餘組件交互,並且隨着是間的推移變得愈來愈複雜。 這種狀況下,使用動態的模擬對象庫效果會比較好,由於他們可以定義單個方法的行爲,而不是考慮全部的方法。
契約紀錄 使用模擬對象讓咱們記錄更多的契約信息,而不止是方法簽名。咱們能夠隨時驗證器樂的。
測試目標 根據經驗法則,若是但願測試組件之間交互,模擬對象可能優於樁對象。模擬庫可以以一種準確的方式來指定交互。而樁該做爲被測試組件使用的那些次要的組件。在這種狀況下,測試的目標是測試被測試組件自己,而不是他與其餘組件之間的交互。
模擬易犯的錯誤 依賴模擬對象會導至許多問題,因此重要的是要知道使用模擬對象不利的一面:
依賴的測試 層疊失敗:一個測試的失敗致使一組測試的失敗。
依賴的代碼只要測時方法依賴於其餘測試方法,就很難以隔離的方式執行這些測試方法。 彼此依賴的測試方法一般會出現這樣的狀況,由於他們共享了一些狀態,而在測試之間共享狀態是很差的。
利用TestNG進行依賴的測試 TestNG經過@Test annotation的兩個屬性(dependsOnGroups和dependsOnMethods)賴支持依賴的測試。
dependsOnMethods的問題: 經過字符串來執行方法名稱,若是未來對他進行重構,代碼就有可能失效。方法名稱違反了」不要重複本身」的原則,方法名稱即在Java方法中用到,也在字符串中使用,另外,等咱們不斷添加新的測試方法時,這個測試用例伸縮性也很差。
利用組來指定依賴關係能夠解決咱們遇到的全部問題:
依賴的測試和線程 當打算並行執行測試時,要記住,線程池中的一個或多個線程將用於依次執行每一個方法。因此,若是打算在不一樣的線程中執行一些測試,過渡的使用依賴的測試將影像執行性能。
配置方法的失敗 依賴測試方法和配置方法之間惟一的不一樣就是,測試方法隱式的依賴於配置方法。
雖然dependsOnMethods能夠處理簡單的測試或之由一個測試方法依賴於另外一個測試方法的狀況,可是在大多數狀況下,您都應該使用dependsOnGroups,這種方式的伸縮性好,面對未來的重構也更爲健壯。
既然咱們提供了準去的依賴信息,那麼TestNG就可以按照於騎的順序來執行測試。
測試隔離並無所以而受到影響。
若是出現層疊式的錯誤,依賴測試能夠加快測試執行速讀。
繼承和annotation範圍
他違反了」不要重複本身」的原則 他爲未來添加測試方法的開發者帶來了負擔。
annotation繼承
全部擴展自BaseWebTest的類都會看到,他們全部的工有方法都自動成爲web.credit-card組的成員。 WebTest變成了一個普通的傳統Java對象(POJO),不帶任何annotation。
集成易犯的錯誤 因爲TestNG的測試方法必須是公有的,在基類中聲明的方法會自動在子類中可見,因此他們永遠也不須要做爲測試類顯式的列出(不要將測試基類列在testng.xml文件中)
測試分組分組解決了上面提到的侷限性,實際上,他們進一步提高了TesgNG的一個設計目標:在靜態模型(測試代碼)和動態模型(執行哪些測試)之間實現清晰的分離。
語法@Test annotation和配置annotation(@BeforeClass, @AfterClass, @BeforeMethod…)均可以屬於分組
test1屬於group2組,test2同時屬於group2組和group3組
分組與運行時刻
這個testng.xml告訴TestNG執行com.example.A類中全部屬於group1組的測試方法。
若是某個方法即屬於包含的組,又屬於排除的組,那麼排除的組優先。 若是既沒有include,也沒有exclude,那麼TestNG將忽略組,執行全部的測試方法。
另外一個功能就是能夠在testng.xml中利用正則表達式來指定組。
在設計組的層次關係時,可以在testng.xml中定義新組帶來靈活性: 能夠在代碼中使用粒度很是小的分組,而後在運行時刻將這些小分組合併成大分組。
執行分組 利用命令行執行
利用ant
利用Mave
利用Java API
排除失敗的測試 建立一個特書的組如broke
而後在運行時刻排除這個組。
組分類
測試類型:單元測試、繼承測試 測試規模:小規模、大規模 功能描述:數據庫、界面 測試速度:慢測試、快測試 過程描述:冒煙測試、發佈測試
讓開發者可以指定方法的分組,主要的好處在於開發者所以可以很容易找出他們須要執行哪些測試。(如剛剛修改了數據庫代碼,可能只須要執行fast和database組測試)
組命名
TestNG可以利用正則表達式來之定要執行的組,若是與這項功能配合使用,這種命名方式就頗有用了。
代碼覆蓋率 類的覆蓋率:類覆蓋描熟了項目中多少類已被測試套件訪問。 方法覆蓋率:方法覆蓋率是被訪問的方法的百分比。 語句覆蓋率:語句覆蓋率追蹤單條源代碼語句的調用。 語句塊覆蓋率:語句快覆蓋率將語句塊做爲基本的覆蓋律單元。 分支覆蓋率:分支覆蓋率也被稱爲判斷覆蓋率。指標計算哪些代碼分支被執行。
覆蓋律工具 Clover、EMMA和Cobertura
成功使用覆蓋率的建議 覆蓋率報告的信息何音的解讀不一樣 覆蓋率很難 百分比沒有意義 爲覆蓋率而設計是錯誤得 有一點好過沒有 覆蓋律工具不會測試不存在的代碼 覆蓋率的歷史講述了本身的故事
企業級測試 單元測試:單元測試對系統中的一個單元進行獨立的測試。
功能測試:功能測試關注一項功能。一般涉及不一樣組件之間的交互。
繼承測試:繼承測試是一種端到端的測試,他會執行整個應用棧,包括全部的外部依賴關係或系統。
一個具體的例子 系統中有一個至關典型的組件,他接收一條JMS消息,其中包含一段有效的XML文本。這段XML文本至關長,描述了一筆財務交易。這個組件的工做是讀出這條消息,解析XML,根據消息的內容條填充一些數據庫的表,而後調用一個存儲過程來處理這些表。
測試內容
咱們將建立一個成功測試。但願確保,若是收到一條有效的XML消息,咱們會正確地處理他,並更新正確的數據表,而後存儲過程的調用也成功。 咱們將摹擬不一樣的場景。但願可以爲測試替工不一樣的XML文本,這樣就可以很容易地不斷添加測試粒子數據。 咱們提供明確的失敗測試。失敗的行爲將被記錄和測試,這樣當組件內部出現失敗時,他的狀態就能夠與測,而且很容易記錄下來。
非測試內容
咱們不測試JMS provider的功能。假定他是一個徹底兼容的實現,已經正確的進行了配置,將成功地提交咱們指望的消息。咱們不執行捕捉全部錯誤得測試。失敗測試應該針對明確的、可重現的失敗場景。咱們不測試API。例如,JDBC去冬的行爲不是測試的主題。確保全部的測試都貫注業務功能,要避免對Java語言的語義進行測試。
測試成功場景 對於JMS API的接口 利用模擬對象(或樁)對象,建立TextMessage實現,用一個簡單的POJO來表現,帶有消息內容和其餘屬性的設置方法。重構該組件,解除業務功能與JMS API的耦合。
構件測試數據
咱們的測試如今接受一個參數,再也不須要本身考慮測試數據的來源,也不須要考慮如何加載測試數據。他要作的只是指定數據提供者。加載XML的實際工做如今代理給了一段獨立的加載程序。
固然,能夠從數據提供者返回一個Object[]的數組,可是,這種方法意味着咱們必需將全部的文件的數據都一次性加載到內存中,由於數組必須事先填充。
測試準備問題
冪等的測試是指,這個測試執行一次和執行屢次的結果是同樣的。若是某個東西是冪等的,那麼說明他在屢次調用時狀態不會改變。
不只須要測試是冪等的,並且測試的次序應該可有可無。因此除了須要是是冪等的以外,測試不該該在狀態或數據方面影像其餘測試。
對於一些寫操做,成功執行以後很容易會對再次執行產生影響,下面方法有助於咱們對付這個問題:
嵌入式數據
在測試準備時初始化數據
事務回滾
選擇正確的策略
錯誤處理
這種方法在於,他們沒能讓咱們區分失敗是不是預期的。相反,咱們應該可以區分預期的成功和預期的失敗。這個測時目前在兩種狀況下會經過:要麼遇到好的數據時會經過,要麼遇到壞數據時會經過。在每種狀況下,咱們都不能肯定會發生些什麼。
一個測試不該該在兩種或兩種以上的狀況下都經過。若是測試驗證了不一樣的失敗狀況,這沒問題,但若是測試在好數據和壞數據的狀況下都經過,那就會致使一些微妙的錯誤,這類錯誤難以被發現。(所以咱們定義了另外一個目錄和數據提供者來處理失敗的狀況)
逐漸出現的單元測試 單元測試不必定是在其它測試以前編寫的,他們能夠是功能測試驅動的。特別是對於大型項目或原有的代碼來講,一開始就編寫有用的單元測試可能很困難,由於在不瞭解全局的狀況下,單元測試可能太瑣碎或不過重要。相反,單元測試能夠從有意義的繼承測試中推導出來,由於調試開發功能測試和集成測試的過程揭示他們所需的單元測試。
對於例子來講咱們須要將XML驗證與數據庫處理放到各自獨立的方法中。這樣就能對他們進行測試
這測重構的結果是咱們獲得了一個簡單的單元測試。
不論測試編寫的次序如何,功能測試和單元測試都是互不的。功能測試是更爲水平化的測試,涉及許多不一樣的組件,執行代碼的不少部分。相反,單元測試是更爲垂直化的測試,他關注範圍狹窄的主題,比功能測試要完全得多。
競爭消費者模式 消費者的執行是併發的,因此咱們必須在測試中進行某種程度的模擬,生產環境中的真實狀況。在咱們這樣做了以後,也但願驗證結果。不論哪一個消費者先開始,也不論哪一個消費者先結束,都沒有關係。咱們但願肯定對於給定數量的消費者,咱們將得道一組已知的結果,能夠進行驗證。
咱們的測試被分紅兩個,一個負責執行消費者,另外一個負責驗證結果。緣由是runConcurrentProcessors會被調用屢次,而咱們只須要在全部方法調用完成以後,對結果驗證一次。爲了表示這種次序,咱們利用了dependsOnMethods這個annotation屬性。
當TestNG發現一個數據提供者時,他將針對數據提供者返回的每一條數據調用一次測試。相似的,當咱們指定調用次數時,TestNG會按照指定的次數調用測試。所以,若是咱們返回數據提供者中準備好的3條數據,那麼每一個線程都會執行3次測試。
所以解決方案是使用一個棧結構,每次調用數據提供者時,返回一條數據,並將這條數據從列表中清除。數據提供者將被調用3次,每次都將爲數據返回不同的數據。
原則:將數據的考慮和功能的考慮分開來是很關鍵的。 在這個例子中,消費者須要的數據應該和實際的測試沒有依賴關係。這種方法意味着,隨着咱們對數據的需求不斷變化,變得更爲複雜,測試自己卻不須要被修改。
一個具體的例子 咱們但願測試一個登陸servlet。這個servlet接受一個請求,檢查用戶名和口令,若是他們有效,就在會話中加入一個標記。代表用戶已登陸。
這個例子展現了重構在測試方面起到的重要輔助做用,說明了即便對於看上去很麻煩、須要一很複雜地方是進行交互的API,頁能夠經過抽象去掉依賴關係。這種抽象意味着 在測試過程當中,咱們能夠利用更簡單的對象,這些對象更容易構造,所以也更容易測試。
增長可測試性的一個反作用就是改進了設計。爲提升可測試性而進行重構,能夠幫助咱們以一種實際的、代碼中的方式來肯定職責和考慮,而這種效果經過畫設計圖是很難達到的。
Java EE測試 容器內測試與容器外測試的對比
容器內測試 優勢:
缺點:
容器外測試 優勢:
缺點:
容器內測試 測試步驟:
建立一個測試環境的實例。 肯定測試。 在測試框架中註冊測試。 註冊一個監聽者來接收搜測試結果。
建立測試環境
肯定測試 假定全部的測試類都在WEB-INF/classes目錄下,咱們能夠遞歸地讀入這個目錄,找到其中全部的類文件。
context是一個ServletContext實例,他是經過調用servlet或JSP頁面獲得的。
註冊測試 註冊測試類的動做告訴了TestNG他要查看的一組類,TestNG將在這組類中查找須要執行哪些測試。他將檢查每一個指定的類,肯定他是否包涵測試方法或配置方法。當全部類都檢查事後,TestNG內部會生成一個依賴關係圖,以決定照到的這些測試的執行次序。
註冊結果監聽者
TestNG自代了3個默認的報告類:
SuiteHTMLRepoter 默認報告類,他在一個目錄下輸出交叉引用HTML文件,讓您能看到某個具體測試的結果。
FailedReporter: 這個報高生成一個TestNG執行配置,該配置包含了全部前一次運行時失敗的測試。他也是默認運行的。
EmailableReporter: 這個報告類生成一個報告文件,能夠很容易地經過電子郵件發送,顯示測試的結果。
默認狀況下,EmailableReporter在磁盤上生成一個文件。
調用TestNG的JSP頁面
Java命名和目錄接(JNDI) JNDI是一個在全局目錄中查找資源的API。能夠把他當作是一個很大的樹型結構,咱們在其中按照名稱查找某個節點。
上面建立一個InitialContext對象,若是在執行容器內執行,會利用供應商提供的API實現,來查找容器內部命名目錄結構。建立了上下文以後,咱們在其中查找對象,列出他的內容,或遍歷這棵樹。全部這些都是經過JNDI API來完成的。InitialContext的構造方法由一個重載的版本,接受一個Hashtable對象做爲參數,其中包含不一樣的環境變量值,決定了上下文應該如何建立。
避免JNDI 組件依賴關係要麼經過服務定位(一般是JNDI)來實現,要麼經過注入來實現。若是您能夠選擇,就採用注入的方式,由於這樣測試的開銷最小,而且這種方式帶來了更大的靈活性。
Java消息服務(JMS)
在測試中使用ActiveMQ
處理狀態 在JMS的例子中,當咱們擁有多個測試時,會引起一個有趣的問題。由於測試是由一對方法組成的,因此讓咱們假定同一個類中還有另外一對發送/接收測試。
一種方法是將發送和接受者放在一個測試中,並在每一個測試方法以前初始化消息代理。請注意兩點都要作到,由於讓消息代裏在一對測試方法以前初始化是比較麻煩的。
另外一種方法是使用消息分撿器。JMS消息分撿器讓咱們可以過濾接收到的消息,這樣能夠只接收與分撿器匹配的消息。
Spring Spring的測試包功能
TestNG經過本身的一組針對Spring的類來解決這些問題,這些類做爲擴展提供。org.testng.spring.test包中包含了全部Spring在其測試包中提供的類,這些類已修改過,能夠用在基於TestNG的測試中。
AbstractSpringContextTests 這是全部Spring測試的基類。他的主要職責是提供上下文的管理。這個類包含一個靜態map,其中包含全部註冊的Spring上下文。
AbstractSingleSpringContextTests 這個類擴展了AbstractSpringContextTests,提供了裝入一個ApplicationContext對象的鉤子。他的子類應該實現getConfigLocation(String[] paths)方法。這個方法返回一個字符串數組,指出了Spring配置文件的位置,一般是從classpath加載的。
Spring的配置方法被聲明在名爲Spring-init的TestNG分組中。咱們沒必要依賴於單個的onSetUp或ontearDown方法,能夠根據須要聲明任意多個@BeforeMethod/@AfterMethod配置方法,只要指定他們依賴於spring-init,就能夠確保他們在Spring執行完準備工做以後獲得調用。
AbstractDependencyInjectionSpringContextTests 這個類提供的最有趣的功能就是向測試注入依賴。測試依賴關係能夠表現爲設值方法或成員字斷。測試也能夠指定Spring應該對他們的樹性執行哪一種類型的自動編織。
這個類有一個事務管理器屬性。由於他派生自支持注入的類,配置文件中必需指定一個PlatforTransactionManager,以便注入。
咱們沒有在測試中指定任何事務行爲,超類自動處理了事務方面的問題,讓每一個測試在他本身的事務中執行,這個十五將在該測試完成以後回滾。
增長的調用setComplete通知超類在測試執行以後應該提交這個事務,而不是回滾。調用這個方法由一個有趣的反作用:這個類中全部後續測試都會提交事務,而不是依賴於默認行爲。
答案在於JUnit和TestNG之間的一個微妙區別。Spring測試假定採用了JUnit的語義。每一個測試類對每一個測試方法都會從新實例化。所以,全部的測試都假定每一個測試開始時,測試時裏的狀態都會復原,但TestNG不是這樣的。
AbstractTransactionalDataSouceSpringContextTests 這個類添加了一些JDBC相關的便利方法。
AbstractAnnotationAwareTransactionalTests 這個類支持超類提供的全部功能以外,這個類容許咱們在測試方法上指定Spring特有的事務annotation,而不是經過編程的方式來指定事務行爲。
Guice 第2章中的例子,對於每一個接口,咱們都有兩個實現。一個是實際的產品實現,他會與一些外部的依賴關係進行交互,如UserDAO對象會與數據庫交互,Mailer對象會與SMTP郵件服務器交互。咱們還有樁對象實現。
Guice注入測試
Spring注入測試
對象工廠
雜談 關注和提供異常 一層遇到了一個沒有預料到的錯誤,不知道如何處理。因此這一層就快樂地向上一層拋出一個異常,但願這個可憐的異常最終會遇到知道怎麼做的人。
吞掉拋出異常
這種方法問題在於,實際上咱們丟試了真實錯誤的有意義的信息。當咱們最後有機會處理這個異常的時候,咱們獲得的信息僅僅是某一層中出了問題,但咱們不知道是在這一曾自己出了問題,仍是更低的層出了問題。
記日誌並拋出
問題在於調用棧常常發生的狀況:信息隱藏。假定一個應用程序有三層或四層,每一層都在日誌中記錄他處裏的異常,查遍8頁的調用棧信息並非最有效地方式。
嵌套拋出
當這個調用棧顯示的時候,沒有絲毫暗示代表背後的緣由是什麼。您必須編寫一個幫助方法,從外面的包裝中取出背後實際的異常。
咱們建議兩種解決方案
避免需檢察異常。運行時異常很合適這樣的狀況。 包裝異常。假如您很是確定在調用棧打印時,背後的緣由會顯示出來,那麼包裝的異常也很好。
有狀態測試 有兩種大相徑庭的狀態分類:不可修改的狀態和可修改的狀態
不可修改的狀態 訪問共享的不可修改的狀態的測試方法,相互之間是獨立的。 由於這些方法都不能修改他們讀到的狀態,因此調用順序能夠是任意的,所以他們沒有違反測試訪法應該彼此肚裏的原則。
可修改的狀態
JUnit會讓這個測試經過,但TestNG不會。 只有當您知道測試方法被調用的順序時,共享可修改的狀態纔有意義。
安全的共享數 安全 不可修改的狀態
安全 可修改的狀態與徹底指定的依賴關係
不安全 可修改的狀態與不肯定的依賴關係
測試驅動開發的缺點 他注重微觀設計超過宏觀測試
他在實踐中難以應用
TDD注重微觀設計超過宏觀設計
測試驅動開發能夠獲得更健壯的軟件,但他也可能致使沒必要要的反覆和過分重構的趨勢,這可能對飲的軟件、設計和最後期限產生負面影響。
TDD難以應用
這種方式獲得的代碼自己並不會優先於傳統方法測試的代碼。
如何建立測試並不重要,重要的是確實要建立測試
測試私有方法 若是他有可能出問題,您就應該測試他。
測試私有方法的比較好的方法是提高方法的可見性,例如,讓他變成保護可見,或者包可見。後者更好一些,由於您能夠把測試和被測類放在同一個包中,而後您就能夠訪問他的全部字段。若是這些方法都不可取,咱們測試私有方法的方式就是利用反射。
咱們利用字符串來描述Java元素。若是您對這些元素進行重命名,這種危險的實踐確定會失效。
咱們利用了該類危險的私有信息。咱們不只假定存在一些私有方法和屬性,並且也假定這個方法將以某種方式修改一個字段。
測試與封裝 若是讓代碼更可測試,不要擔憂破壞封裝。可測試星應該賽過封裝。
讓一個私有方法(或字段)成爲包可見的、保護可見的或公有的。
去掉方法的final限定符。這讓測試勒可以擴展這些類,或重寫這些方法,模擬或稍微改變他們的實現,從而讓系統的其它部分更可測試。
記日誌的最佳實踐 在出錯時,輸出錯誤或警告是合理的。可是對於警告的狀況,重要的是肯定這是否是該作的事情。咱們添加的每一條無用的日誌信息都會干擾有用的信息,所已精心選擇是有意義的。
對於調試需求,記日誌是有用的。可是,只要有一個開關能打開或關閉,絕大多數的記日誌需求都可以知足了,不須要複雜的解決方案。