系列目錄html
在開始本篇以前須要補充一些內容,經過前面搭建Nunit測試環境咱們知道要使一個方法成爲單元測試方法首先要在此方法所在類加上TestFixture註解,而且在該方法上添加上Test註解.
然而還有一點須要注意:全部進行單元測試的方法必須標識爲public訪問級別,不然沒法識別爲單元測試方法數組
此外,單元測試方法還有如下特徵sass
單元測試方法不能帶有參數
這裏說的不能是指不能像普通方法同樣帶有普通的參數(能夠帶基於註解的特殊參數)
若是像普通方法同樣帶參數,雖然編譯能經過,可是運行時會拋出異常.less
單元測試方法不能重載
這裏說的不能是不該該,實踐中是能夠的,可是重載方法會帶來無盡的麻煩,讀者能夠本身實踐一下.
進行單元測試無非就是對不一樣參數引發方法出現不一樣結果的斷言(通常狀況下全部的單元測試方法都有斷言)下面咱們來看Nunit中最基本最經常使用的斷言異步
Assert.True用於斷言布爾參數是否爲true
Assert.True的重載方法還支持可空布爾參數單元測試
Assert.True還支持自定義錯誤提示
上面代碼改成以下測試
若是返回錯誤的時候,咱們自定義的錯誤信息就會顯示出來.3d
其它的斷言方法也大都有此重載代碼規範
此斷言方法爲Assert.True的親兄弟,兩者功能如出一轍.code
與Assert.True斷言狀態相反,斷言某一參數的結果爲false
這裏須要特別說明的是,單元測試應該力求簡單,明瞭,斷言尤爲如此.
上面的斷言還也能夠寫成
Assert.False(!firstCondition);
這和斷言變量firstCondition爲true最終功能同樣,可是看上去很不直接明瞭,一般狀況下我見到Assert.False第一反應就是斷言一個變量爲False,這裏則反其道行之,其實是斷言一個變量爲true,這種狀況應當避免.
Assert.False的親兄弟,兩者表現如出一轍
Nunit Assert類還有還多其它的前面帶有Is的方法,它們都和不帶Is的如出一轍,其中帶Is的是爲了兼容老版本寫法.
用於斷言一個變量是否爲null,這裏再也不舉例,可是實際中用的卻比較多.
用於斷言一個變量不是null,它和Assert.Null()功能相同,只是斷言的狀態相反.
Nunit裏還有其它的前綴有Not的方法,它和不帶Not的方法用法同樣,只是斷言的狀態相反
Assert.Throws
用於斷言特定方法在運行的時候會拋出異常.此方法有泛型版本,異步版本,這裏僅對異步版本進行說明
因爲示例愈來愈複製,咱們不能只在測試方法內寫一些簡單代碼進行測試了,這裏咱們新建一個Person類以下
這個類裏面包含一個WhetherNameContainsB方法,用於判斷實例的Name是否包含字母B,
這個方法裏面有三個邏輯分支,單元測試的時候每個都要覆蓋到,這裏咱們斷言若是name爲null則拋出ArgumentNullException
咱們編寫以下單元測試方法
運行這個測試,則會返回成功狀態,由於預期的異常出現了.
用於斷言字段串是否爲空字符串.
用於斷言數字類型(int,long,float,double,decimal等)爲正數(大於零的數)
其實不少斷言均可以斷言均可以用Assert.True來完成,好比斷言一個數是否爲正數,能夠用Assert.True(a>0),這裏因爲a只是一個普通變量,使用a>0做爲條件主義仍然十分清析,然而到了後面有咱們不只要判斷一個變通變量,還要判斷lambda表達式,若是條件過於複雜,則語義會變得不是特別清析了,使用Assert自帶的靜態方法主義會更加清析,可讀性更高.
用於斷言數字類型爲負數(小於零,不包括零)
用於斷言數字類型爲數字零
用於斷言數字類型不是零.
不少時候,Not包含的範圍很是廣,進行單元測試是爲了在開發階段找出問題,解決問題,所以斷言的範圍越窄越好,咱們不能僅僅讓單元測試經過了事.
好比一個方法返回的結果是數字類型,咱們要判定它是正數?大於某一個數的正數?在必定範圍的正數?是一個具體的正數?而不能簡單的是零,不是零.固然這還要根據業務自己來確實,有些時候範圍可能確實很大,可是必定要注意單元測試原則.
用於斷言數字類型的變量大於(或者等於)某一個值
用於斷言數字類型小於(或者等於)某一值
用於斷言集合中是否包含某一元素.
好比如下方法,用於斷言字符串數組中是否包含特定字符串
用於斷言兩個對象是否相等
這個靜態方法並無提供重載參數用於指定一個比較器來比較引用對象的相等性,須要實現equals和gethashcode方法才能獲得預期結果,但在實際中咱們每每把比較器放在類外邊,如何在比較引用對象的時候加載一個比較器在後面章節會有介紹,這裏先略過.
上面一篇咱們講解了一些基本斷言,利用這些斷言咱們就能夠進行單元測試了,然而僅僅使用簡單斷言仍是不夠的,若是邏輯複雜度較高,使用簡單的斷言會致使單元測試代碼量增長,最終致使單元測試自己過於複雜和難以維護.須要說明的是這裏所說的複雜斷言仍然在Assert的靜態方法裏面,自己也不是特別複雜,只是比前面講的秒複雜一些,只是若是沒有了這些方法,一些特殊功能實現起來比較費勁基本沒法實現.
下面就介紹一下這些方法.
Assert.Catch有泛型和異步方法,這裏只介紹其泛型方法.不少即便常用單元測試功能的人也未必用過這個方法.
其實這個方法和Assert.Throw用法上相似,只是有一點不一樣的是要測試的方法裏的異常能夠是catch到的異常的子類,實際開發中,若是咱們能確立異常的類型,則最好捕獲具體類型異常,然而不能排除有一些不夠規範的代碼整段代碼被一個try catch包圍,這時候不必定可以捕獲到想要的特定異常,這時候可使用Assert.Catch
以上代碼相似上一節中講throw時使用的代碼,只是這裏泛型參數裏是Exception而不是具體的異常信息,咱們運行這段代碼,依然可以測試經過.
在單元測試中,期待的狀態越具體越好,然而因爲種種緣由(好比立項時候沒有對代碼規範作過多要求,開發者水平不高,要測試的代碼是別人寫的,寫單元測試的人對其中邏輯並非特別清楚等)咱們沒法作到很是具體,這個時候能夠把要得到的狀態放寬之後,待條件完備了再修改單元測試以進一步收窄狀態.
Assert.Ignore和Ignore註解功能相似,能夠在測試的時候忽略一個單元測試.有些狀況下咱們須要暫時忽略一個測試,好比說要進行測試的內容有一個外部依賴,如今外部依賴暫時不可用,若是咱們不忽略的話測試將會失敗,在自動化環境下,失敗將致使沒法進行下一步動做,此時咱們能夠暫時忽略這個測試.
忽略的測試前面有一個 黃色歎號標誌,警示咱們須要注意.
咱們先看一下面一段代碼
在這個單元測試自己使用到了try catch,咱們知道WhetherNameContainsB方法在Person類的Name沒有提供值的狀況下會拋出異常,然而咱們的代碼並無斷言這個異常存在,此時因爲catch代碼塊存在,會把異常吞掉,所以最終咱們斷言person的Age爲正數的時候將會經過(咱們在構造類的時候設置了Age爲32)
這顯然不行的,這時候我把們Assert.Fail(e.Message)取消註釋,測試便會變成失敗狀態.
用於斷言一個Double類型數字是不是NaN
雖然實際業務中咱們並不會寫以上代碼,可是若是除數和被除數是經過複雜計算得來的則有可能除數和被除數都是零.
用於斷言一個對象是不是指定類型的實例,
如上psn是Person類的一個實例,而Person繼承自Object,所以psn也是Object類的實例
此方法和以上方法做用相反,它用來斷言指定類型是當前對象類型的子類.(Assert.IsInstanceOf判斷的是當前對象是指定類型的子類)
這個方法語義不是很明確,很容易搞暈,使用的時候須要特別注意
用於使一個測試經過,可是出現警示信息.