Junit系列一 基本概述

JUnit是一個開源的java自動化單元測試框架。由 Erich Gamma 和 Kent Beck 與1997年開發完成。 Erich Gamma 是 GOF的作者 之一;Kent Beck 則在 XP 中有重要的貢獻。Junit常常被開發者用來做單元測試的自動化測試框架。但是按照測試人員的角度來說,Junit更嚴格來講是一個測試驅動器,我們不僅僅可以用其來做單元測試,也是可以以其為核心來做集成測試、系統測試。很多人分析Junit喜歡從開發角度從設計模式來分析,但是對于測試人員來說需要的是從中學習自動化測試框架的基本組成部分與結構模式。學習Junit不僅僅是學習其用法,更要從中學習一個自動化測試框架的有哪些組成部分?各個組成部分之間是如何協調運作來形成一個可擴展穩健的自動化測試框架。Junit可謂“麻雀雖小,五臟俱全。”,其包含一個自動化測試框架所有的要素部分,很多的測試框架,千變萬化其實都離不開一個測試框架必有的組件與模式。本系列嘗試從一個手工測用例轉化為自動化執行以后的模式,來總結出一個自動化測試所必須的一個組成部分,并借用Junit來說明Junit中是如何實現這幾個部分的。

基本概述

讓我們從平時做測試的一個簡單情形開始。想想平時我們是如何做測試的,或者說是如何執行測試過程的?是不是有用例?我們編寫了用例,在用例里面說明了測試預置環境,測試輸出數據,執行步驟,和預期的結果。例如:

拿到這個用例,是不是要一步步按照用例的說明來操作。在人工測試的情況下類似如下的情況,

在這個過程當中,測試人員是執行者,讀取測試用例內容,操作被測對象,并判斷結果是否正確。

那么,如果要把上述的過程自動化需要如何做呢?在自動化的過程中,人不在了,那么誰來讀取測試用例呢?準確點說由誰來讀取測試用例的文件,并逐條執行里面的用例呢?首先想到就是寫一個程序,此程序能讀取文件,并識別里面的逐條的測試用例,然后執行。這樣的一個程序叫做測試執行器(Test Runner)。

有了執行器以后,又面臨一個問題,在人工操過程中,人是可以識別文件里的文本用例,讀懂它的步驟然后操作,但執行器就不行了,它是程序他無法識別文本的意思。程序識別程序,那么自然而然想到的方法就是把測試用例方法化,即把測試用例用程序的方法來表示,即測試方法(Test Method),因此執行器執行用例,就轉化為執行器調用方法的過程。

我們進一步觀察,測試方法,實時上,一個方法()Test Method 就代表一個測試用例,一個測試用例主要包含的重要信息,就是用例的執行環境是什么,執行步驟,預期值是什么,等等。類似的測試方法也需要包含四個步驟,稱為測試四步驟(Four-Phase Test)

  • 環境設置
  • SUT調用
  • 結果驗證
  • 環境清理

回顧之前所述,在測當中一個重要的步驟就是驗證,手動測試中,肉眼查看運行結果并和預期對比來得出測試是否通過的結果。在自動化過程中自然需要這個過程,讓測試方法自動驗證測試結果呢?這部自動化測試中稱為斷言(Assert)。

在整個的測試過程當中還包過如何過濾測試方法、、測試數據管理、最終測試結果報告等等。

如上述,我們總結一下,在自動化測試當中需要涉及的部分包括:

  • 測試執行器(Runner):讀取測試用例、執行測試用例、測試報告輸出
  • 測試輸入數據管理:如果測試需要外部輸入數據,這些數據如何組織管理
  • 環境設置(setUp tearDown):主要設置用例執行前的環境、測試結束后清理測試環境;
  • 結果斷言(Assert):如何來判斷測試結果是否符合預期
  • 測試組織與流程控制:如何來組織測試用例,測試用例的過程如何控制

那么作為一個自動化的測試框架,Junit如何對上述各個組成部分進行處理呢,我們將從一個Junti入門例子開始,先對Junit做大致介紹,然后逐一演示Junit是如何實現上述各個部分的?只要大家理解了Junit對上述幾個部分是怎么做的,后續學習其他測試驅動器就可以快速入手,比如TestNG-在講完Junit后,我們會針對TestNG如何實現上是問題做簡單說明,只要大家牢固掌握Junit實現上述問題的本質,學習testNG也就是分分鐘的事情。

在Eclipse中使用JUnit4

在開始之前我們先把Junit引入到我們的Eclipse的項目中來,在Eclipse項目右鍵選中,如下圖所示

在彈出的屬性窗口中,首先在左邊選擇“Java Build Path”,然后到右上選擇“Libraries”標簽,之后在最右邊點擊“Add Library…”按鈕,如下圖所示:

然后在新彈出的對話框中選擇JUnit4并點擊確定,如上圖所示,JUnit4軟件包就被包含進我們這個項目了。

Junit 入門例子

假設我們有一個計算器類,包含兩個方法,add和multiply。

public class Calculator {
    
    public int add(int one, int another) {
        return one + another;
    }

    public int multiply(int one, int another) {
        return one * another;
    }
}

對這兩個方法,我們寫兩條happy path的測試用例:

要把這兩條測試用例自動化執行,要涉及前面所述的幾個步驟,首先是要測試用例腳本化,把測試用例的步驟用代碼方法來表示,我們建一個類叫CalculatorTest,包含這兩條測試用例:

public class CalculatorTest {
    
    public void testAdd(){
        
        Calculator calculator = new Calculator();
        int sum = calculator.add(6,7);
        if(sum == 13) {
            System.out.println("add() SUCCESS!");
        } else {
            System.out.println("add() FAIL!");
        }
    }
    
    public void testMultiply(){
        
        Calculator calculator = new Calculator();
        int product = calculator.multiply(8,9);
        if (product == 56) {
            System.out.println("multiply() SUCCESS!");
        } else {
            System.out.println("multiply() FAILs!");
        }
    }   
}

測試方法是不是要執行器來執行?如果我沒有Junit這樣的框架,我們怎么執行上述的測試方法呢?如下也許是一種方法:

public class Client {
    public static void main(String[] args) {
        CalculatorTest test = new CalculatorTest();
        test.testAdd();
        test.testMultiply();
    }
}

然后再通過某種方式運行這個main 方法,查看打印的輸出,來驗證測試是成功還是失敗。想想一下,如果我們有很多的類,每個類都有很多方法,每個方法都要寫很多的分支來判斷結果,而且還要寫個main方法一個個去調用各個類方法,明顯是不可行呢?如果有一個程序--執行器,能夠自動創建一個測試類,并自動調用里面的各個測試方法那么就簡化很多了。Junit框架就提供了這樣的功能,Junit內置的執行器,能夠讀取一個類,并執行里面的測試方法,要讓執行者自動找到測試方法并調用,必須要有一定的約定,比如告訴執行器說用test開頭的方法就是測試方法(Junit 3所采用的方法)或者給測試方法某個標注來表示測試方法,那么執行器就會按著這個約定去調用類里的有特定命名方式或者有特定標志的測試方法。我們來Junit來改寫上述的測試:

public class CalculatorTest {
    
    @Test
    public void testAdd(){
        
        Calculator calculator = new Calculator();
        int sum = calculator.add(6,7);
        if(sum == 13) {
            System.out.println("add() SUCCESS!");
        } else {
            System.out.println("add() FAIL!");
        }
    }
    
    @Test
    public void testMultiply(){
        
        Calculator calculator = new Calculator();
        int product = calculator.multiply(8,9);
        if (product == 56) {
            System.out.println("multiply() SUCCESS!");
        } else {
            System.out.println("multiply() FAILs!");
        }
    }       
}

大家注意到每個測試方多了一個注解@Test,這個注解的作用的就是告訴Junit的Test Runner 這是一個測試方法,Test Runner就會調用這個方法。這時候你就不用自己寫一個main來執行這些方法,在Eclipse下右鍵 Run as Junit Test,Junit的測試執行器就會自動運行里面的測試方法。

還有兩個地方:一個是設置部分,每個測試方法都創建了一個Calculator,這個重復的代碼是否可以抽取出來呢?還有判斷結果部分分支復雜,能否簡化了?Junit提供fixture和斷言Assert相關方案來解決這兩個問題,看再一次用Junit簡化后的測試代碼:

public class CalculatorTest {
    
    // fixture部分
    public Calculator calculator;
    
    @Before
    public void setUp(){
        calculator = new Calculator();
    }
    
    //測試方法
    @Test
    public void testAdd(){
        
        calculator = new Calculator();
        int sum = calculator.add(6,7);
        //斷言部分
        Assert.assertEquals(13, sum);
    }
    
    @Test
    public void testMultiply(){
        
        calculator = new Calculator();
        int product = calculator.multiply(8,9);
        //斷言部分
        Assert.assertEquals(72, product);   
    }       

}

上述@Berfore 表示此方法在每個測試方法運行之前運行一次。Assert.assertEquals判斷實際結果與預期是否一致。至此,這就是一個簡單完整的Junit測試代碼。用Junit執行器運行后有如下圖的測試結果展示:

上述的代碼中有疑問的地方先不管,這只是讓大家體會一些一個Junit測試的整體流程,各個注解后面會有詳細介紹。這邊講一些測試的統一結構和命名問題。

統一的測試結構

回顧我們的第一個Junit測試,可以總結出一個良好的測試方法包含四個步驟,就是上回我們提到的:

  • 設置:稱為Fixture
  • 執行:掉測試方法
  • 斷言:判斷結果是否預期
  • 清理:清理測試,相關例子后續會看到

極力建議再寫測試過程中中應該在每個階段開始時做好注釋。

測試方法命名規則

Junit4之前,注解,Junit必須采用一種方法來區分普通的方法和測試方法,當時采用的辦法標識 以test為前綴的方法名、public、非static、void、無參的方法為測試方法,因此,測試方法名稱都testFoo,testBar諸如此類。

但是Junit設計師認為這種的命名方式有時候無法真實揭示測試方法真實的用意,當一個方法對應的測試方法多了以后,甚至還會造成一些混亂,因此在Junit采用@Test注解來標識測試方法后,Junit取消測試方法名稱必須test開頭的規定,而是可以隨意命名,但是大部分人還是以test開頭。

后面有人提出 行為表達式(Behavior-expressing patterns)的命名方式:

[UnitOfWork_StateUnderTest]

下劃線可以用with、if 等此替換。這種方式的作用是希望能讓測試用例和代碼文檔一樣易于閱讀,比如上述的代碼寫久了,回頭去看不知道方法testMultiply在乘積溢出情況下會返回什么,如果你的測試名稱是這么寫的:

multiplyOverflowWithException()

那么看測試方法的人就知道這測試方法,在溢出時會拋異常

集體怎么命名取決與你們的團隊是如何約定,看個人喜好。

總結

我們討論手工測試自動化后,需要處理的幾個步驟,包括測試方法的讀取與執行、測試執行環境的設置、測試結果的判斷、測試報告、測試數據的管理、測試用例的組織等方面,一般的自動化測試框架要解決也就這幾個方面,對于Junit testNg無不如此。對于Junit 我們將從測試執行、斷言、執行器、異常測試、測試組織等幾個大方面詳細介紹它的使用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,829評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,923評論 6 342
  • 1.測試與軟件模型 軟件開發生命周期模型指的是軟件開發全過程、活動和任務的結構性框架。軟件項目的開發包括:需求、設...
    宇文臭臭閱讀 6,745評論 5 100
  • 1.測試與軟件模型 軟件開發生命周期模型指的是軟件開發全過程、活動和任務的結構性框架。軟件項目的開發包括:需求、設...
    Mr希靈閱讀 21,983評論 7 278
  • 簡介 測試 在軟件開發中是一個很重要的方面,良好的測試可以在很大程度決定一個應用的命運。軟件測試中,主要有3大種類...
    Whyn閱讀 5,812評論 0 2