詳解Junit4單元測試框架的應用

引言

這篇文章將幫你瞭解如下內容:

單元測試框架如何在自動化測試中應用;

junit4如何上手;

junit4的高級功能有哪些;

junit4中用例併發和用例失敗重試的方案;

單元測試

單元測試(Unit Testing),是一種軟件測試方法,通過這種測試方法測試各個源代碼單元,一個或者多個模塊的集合,使用程序來測試程序,來保證它們的可用性。一般來說單元測試由開發人員自己來執行。單元測試是由開發人員編寫的一段代碼,用於檢查被測試代碼的一個小的、明確的功能是否正確。由於近些年來ui自動化測試和接口測試的流行,單元測試也被引入到自動化測試領域,我們通常編寫的自動化測試腳本都是基於單元測試框架。不同的語言有其對應的單元測試框架。例如:Java的主流單元測試框架包括:Junit4\TestNG;Python的主流單元測試框架包括:unittest\pytest等等。

Junit概念

Junit是一個可編寫重複測試的簡單框架,是基於Xunit架構的單元測試框架的實例。Junit4最大的改進是大量使用註解(元數據),很多實際執行 過程都在Junit的後臺做完了,而且寫test case 的類不需要繼承TestCase,只需要在所要做test case的方法前加@Test 註解即可。Junit被默認的作爲Eclipse插件,集成到Eclipse中。

新特性:

(1)、使用junit4.x版本進行單元測試時,不用測試類繼承TestCase父類

(2)、junit4.x版本,引用了註解的方式,進行單元測試;

Junit4環境搭建

Java 工程中add Library

 

選擇Junit4 點擊Finish按鈕

 

Junit4的常用註解

junit4.x版本我們常用的註解:

A、@Before 註解:與junit3.x中的setUp()方法功能一樣,在每個測試方法之前執行;

B、@After 註解:與junit3.x中的tearDown()方法功能一樣,在每個測試方法之後執行;

C、@BeforeClass 註解:在所有方法執行之前執行;

D、@AfterClass 註解:在所有方法執行之後執行;

JUnit4的用例執行順序是:@BeforeClass> @Before> @Test1> @After>@Before> @Test2> @After….. @AfterClass

E、@Test(timeout = xxx) 註解:設置當前測試方法在一定時間內運行完,否則返回錯誤;

F、@Test(expected =Exception.class) 註解:設置被測試的方法是否有異常拋出。拋出異常類型爲:Exception.class;

G、@Ignore 註解:註釋掉一個測試方法或一個類,被註釋的方法或類,不會被執行。

H、@RunWith註解:指定用例的運行Runner,是用來修飾類的,而不是用來修飾函數的。只要對一個類指定了 Runner ,那麼這個類中的所有函數都被這個 Runner 來調用。

assertThat

JUnit 4.4 結合 Hamcrest 提供了一個全新的斷言語法——assertThat。assertThat 使用了Hamcrest 的Matcher 匹配符,用戶可以使用匹配符規定的匹配準則精確的指定一些想設定滿足的條件,具有很強的易讀性,而且使用起來更加靈活。使用assertThat 需要導入:

import static org.hamcrest.CoreMatchers.*;

assertThat的主要功能如下

一般匹配符

1、assertThat(testedNumber, allOf( greaterThan(8), lessThan(16) ) );

註釋: allOf匹配符表明如果接下來的所有條件必須都成立測試才通過,相當於「與」(&&)

2、assertThat(testedNumber, anyOf( greaterThan(16), lessThan(8) ) );

註釋:anyOf匹配符表明如果接下來的所有條件只要有一個成立則測試通過,相當於「或」(||)

3、assertThat(testedNumber, anything() );

註釋:anything匹配符表明無論什麼條件,永遠爲true

4、assertThat(testedString, is( "developerWorks" ) );

註釋: is匹配符表明如果前面待測的object等於後面給出的object,則測試通過

5、assertThat(testedString, not( "developerWorks" ) );

註釋:not匹配符和is匹配符正好相反,表明如果前面待測的object不等於後面給出的object,則測試通過

字符串相關匹配符

1、assertThat( testedString,containsString( "developerWorks" ) );

註釋:containsString匹配符表明如果測試的字符串testedString包含子字符串"developerWorks"則測試通過

2、assertThat(testedString, endsWith ( "developerWorks" ) );

註釋:endsWith匹配符表明如果測試的字符串testedString以子字符串"developerWorks"結尾則測試通過

3、assertThat(testedString, startsWith ( "developerWorks" ) );

註釋:startsWith匹配符表明如果測試的字符串testedString以子字符串"developerWorks"開始則測試通過

4、assertThat(testedValue, equalTo( expectedValue ) );

註釋: equalTo匹配符表明如果測試的testedValue等於expectedValue則測試通過,equalTo可以測試數值之間,字符串之間和對象之間是否相等,相當於Object的equals方法

5、assertThat(testedString, equalToIgnoringCase( "developerWorks" ) );

註釋:equalToIgnoringCase匹配符表明如果測試的字符串testedString在忽略大小寫的情況下等於"developerWorks"則測試通過

6、assertThat(testedString, equalToIgnoringWhiteSpace( "developerWorks" ) );

註釋:equalToIgnoringWhiteSpace匹配符表明如果測試的字符串testedString在忽略頭尾的任意個空格的情況下等於"developerWorks"則測試通過,注意:字符串中的空格不能被忽略

數值相關匹配符

1、assertThat(testedDouble, closeTo( 20.0, 0.5 ) );

註釋:closeTo匹配符表明如果所測試的浮點型數testedDouble在20.0±0.5範圍之內則測試通過

2、assertThat(testedNumber, greaterThan(16.0) );

註釋:greaterThan匹配符表明如果所測試的數值testedNumber大於16.0則測試通過

3、assertThat(testedNumber, lessThan (16.0) );

註釋:lessThan匹配符表明如果所測試的數值testedNumber小於16.0則測試通過

4、assertThat(testedNumber, greaterThanOrEqualTo (16.0) );

註釋: greaterThanOrEqualTo匹配符表明如果所測試的數值testedNumber大於等於16.0則測試通過

5、assertThat(testedNumber, lessThanOrEqualTo (16.0) );

註釋:lessThanOrEqualTo匹配符表明如果所測試的數值testedNumber小於等於16.0則測試通過

collection相關匹配符

1、assertThat( mapObject,hasEntry( "key", "value" ) );

註釋:hasEntry匹配符表明如果測試的Map對象mapObject含有一個鍵值爲"key"對應元素值爲"value"的Entry項則測試通過

2、assertThat(iterableObject, hasItem ( "element" ) );

註釋:hasItem匹配符表明如果測試的迭代對象iterableObject含有元素「element」項則測試通過

3、assertThat( mapObject,hasKey ( "key" ) );

註釋: hasKey匹配符表明如果測試的Map對象mapObject含有鍵值「key」則測試通過

4、assertThat( mapObject,hasValue ( "key" ) );

註釋:hasValue匹配符表明如果測試的Map對象mapObject含有元素值「value」則測試通過

Junit4應用

創建一個junit4用例

New>選則JUnit Test Case

 

 

選擇New Junit4 test,點擊Finish即完成了一個Junit4 用例的創建工作

 

實例代碼

publicclass Junit4Demo {

       @BeforeClass

       public static void setUpBeforeClass()throws Exception {

       }

       @AfterClass

       public static void tearDownAfterClass()throws Exception {

       }

       @Before

       public void setUp() throws Exception {

       }

       @After

       public void tearDown() throws Exception {

       }

       @Test

       public void EmptyCollection() {

              Collection collection =newArrayList();

              assertTrue(collection.isEmpty());

              }

       @Test

       public void MyString() {

              assertEquals("Test",newString("Test"));

              }

       @Test

      public void MyNull() {

              assertEquals(null,"abc");

              }

}

執行多個測試用例

執行多個測試用例的意義是將多個測試用例通過suite管理起來。

New一個Test Suite,點擊Next

 

可以自定義需要執行的測試用例

 

點擊Finish,生成代碼如下:

importorg.junit.runner.RunWith;

importorg.junit.runners.Suite;

importorg.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)

@SuiteClasses({Junit4Demo.class, Junit4Demo2.class })

publicclass AllTests {

 

}

使用@Rule擴展Junit4

Rule是JUnit4中的新特性,它讓我們可以擴展JUnit的功能,靈活地改變測試方法的行爲。JUnit4中包含兩個註解@Rule和@ClassRule用於修飾Field或返回Rule的 Method,Rule是一組實現了TestRule接口的共享類,提供了驗證、監視TestCase和外部資源管理等能力。JUnit提供了以下幾個Rule實現,必要時也可以自己實現Rule。

Verifier: 驗證測試執行結果的正確性。

ErrorCollector: 收集測試方法中出現的錯誤信息,測試不會中斷,如果有錯誤發生測試結束後會標記失敗。

ExpectedException: 提供靈活的異常驗證功能。

Timeout: 用於測試超時的Rule。

ExternalResource: 外部資源管理。

TemporaryFolder: 在JUnit的測試執行前後,創建和刪除新的臨時目錄。

TestWatcher: 監視測試方法生命週期的各個階段。

TestName: 在測試方法執行過程中提供獲取測試名字的能力。

簡單的說就是提供了測試用例執行過程中一些通用功能的共享的能力,使我們不必重複編寫一些功能類似的代碼。JUnit用於標註Rule的註解包括@Rule和@ClassRule,區別在於作用域不同@Rule的作用域是測試方法,@ClassRule則是測試Class。

自定義Rule實例:

自定義一個rule, 實現循環執行一個方法,代碼如下:

importjava.util.Arrays;

importorg.junit.rules.MethodRule;

importorg.junit.runners.model.FrameworkMethod;

importorg.junit.runners.model.Statement;

 

classRepeatableRule implements MethodRule{

 

       int times=1;

       String[] testMethods = null;

 

       RepeatableRule(int times, String[]testMethods){

              this.times = times;

              this.testMethods = testMethods;

       }

 

       @Override

       public Statement apply(final Statementbase, final FrameworkMethod method, Object target) {

        return new Statement() {

         @Override

         public void evaluate() throwsThrowable {

               intloopTime = 1;

               if(Arrays.asList(testMethods).contains(method.getName())){

                      loopTime= times;

               } 

               for(inti=0;i

                base.evaluate();

         }

      };

       }

}

調用自定義的rule

importorg.junit.After;

importorg.junit.Before;

importorg.junit.Rule;

importorg.junit.Test;

importorg.junit.rules.MethodRule;

 

publicclass TestCase {

 

       @Rule

       public MethodRule rule = newRepeatableRule(5, new String[]{"test1"});

 

       @Before

       public void setUp() throws Exception {

       }

 

       @After

       public void tearDown() throws Exception {

       }

 

       @Test

       public void test() {

              System.out.println("test");

       }

       @Test

       public void test1() {

              System.out.println("test1");

       }

 

}

執行用例可以看到用例 test1被執行了5次。

用例併發執行與出錯重試機制

Junit4併發不便利往往是其被TestNG用戶詬病的原因,其實我們可以使用Maven的maven-surefire-plugin插件解決這個問題,而這一方法也是在持續集成過程中運行自動化測試用例最常用的解決方案之一。maven-surefire-plugin是一個用於mvn 生命週期的測試階段的插件,可以通過一些參數設置方便的在testNG或junit下對測試階段進行自定義。在實際工作中我們可以利用該插件指定運行的測試用例,並通過多線程的方式來運行用例,我們僅僅需要配置參數<threadCount>即可,例如:<threadCount>3</threadCount>,表示用3個線程執行測試使用。更爲方便的是我們還可以通過參數<rerunFailingTestsCount>來控制重新運行失敗的測試用例的執行次數。例如:<rerunFailingTestsCount>2</rerunFailingTestsCount>,表示用例失敗後將再重新執行2次。關於詳細使用maven-surefire-plugin插件的方法請參考文章:

詳解maven-surefire-plugin在自動化測試中的應用