天天看點

Android單元測試系列

前沿:

Android SDK 測試類是基于Junit3來進行擴充的,是以我們有必要了解Junit3,本文将詳細介紹Junit3的相關知識。

1.什麼是 JUnit

Android單元測試系列

2.JUnit 的運作模式

1.定義測試代碼:這也就是 JUnit 中所謂的 TestCase,根據源代碼的測試需要定義每個TestCase,并将 TestCase 添加到相應的 TestSuite 友善管理。

2.管理測試用例:修改了哪些代碼,這些代碼的修改會對哪些部分有影響,通過 JUnit 将這次的修改做個完整測試。這也就 JUnit 中所謂的 TestSuite。

3.定義測試環境:在 TestCase 測試前會先調“環境”(如:參數化測試環境,套件測試環境)配置,在測試中使用,當然也可以在測試用例中直接定義測試環境。

4.檢測測試結果:對于每種正常、異常情況下的測試,運作結果是什麼、結果是否是我們預期的等都需要有個明确的定義,JUnit 在這方面提供了強大的功能。

簡單來說就是: TestCase -> TestSuite -> TestRunner ==> TestResult      

3.如何在AndroidStudio上搭建Junit測試環境

版本:Window 7旗艦版

IDE:Android studio 2.2.3

gradleVersion :gradle 2.2.3

3.1 我們需要先搭建一個Junit的運作環境,由于我們是基于Android的單元測試系列,是以我們将介紹如何在Android Studio中搭建Junit運作環境:

Android單元測試系列

在Adroid 視圖模式下,可以看到一個test 和 androidTest兩個檔案夾。Test檔案夾是進行本地測試,而androidTest 是功能性測試,在本文屬于單元測試,不需要連接配接具體的模拟器或者真機,單元測試代碼寫在Test檔案夾裡面。

編寫一個簡單的Junit3測試用例

1.選中待測試類中具體的方法。右擊goto—>Test 彈出如下視窗進行簡單操作,就可以生成一個junit3的單元測試。(更改頁籤也可以生成 junit4 的單元測試)

Android單元測試系列
public class MathUtilTest extends TestCase {


    public void setUp() throws Exception {
        super.setUp();
      System.out.print("開始.......\n");
    }

    public void testAdd() throws Exception {
        System.out.print(".testAdd      \n");
        assertEquals(2, MathUtil.add(1, 1));
    }

    public void testAdd1() throws Exception {
        System.out.print(".testAdd1      \n");
        assertEquals(2, MathUtil.add(2, 2));
    }

    public void tearDown() throws Exception {
        System.out.print("結束.......\n");
    }

}      

1.在Junit3,為了更好的管理項目,建議将測試類放在與源代碼同包名下的目錄下

Android單元測試系列

2.命名建議原類名+TestCase

3.unit3中規定具體運作的測試方法必須要以test開頭,後面的自己另起。于是就有了測試方法test_add()(為了清晰,我個人習慣用下劃線命名規則來命名測試方法)

4.測試 的方法有了,那麼我們根據什麼來判斷這個測試方法是否通過呢,沒錯,就是通過assertEquals(期望值,實際值)方法來進行斷言,由于我們知道1+1肯定等于2,于是我們就斷言如果方法MathUtil.add(1, 1)的結果肯定為2,于是就有了assertEquals(2, MathUtil.add(1, 1));

運作

右擊方法就方法選擇Run->testadd()

Android單元測試系列

6.運作結果,因為實際值與期望值相同是以就通過了

Android單元測試系列

7.當然如果和期望的值不相等就會出現異常情況。

Android單元測試系列

可以看到測試用例結果顯示,一個通過一個沒有通過。沒有通過原因也寫出來了,Expected 值和Actual值不相等。

Android單元測試系列

junit3測試有幾明顯的地方。

1.測試方法必須以test開頭否則無法識别

2.需要繼承TestCase類。

斷言

TestCase類是繼承自Assert,是以預設擁有下面的斷言方法,具體也可以參考源碼(junit.framework.Assert)中支援的斷言方法

Android單元測試系列

setUp&&tearDown

Junit3中TestCase提供了 setUp 和 tearDown方法:

setUp():在每個測試方法之前調用,一般用于初始化

tearDown():在每個測試方法執行完畢之後調用,一般用于資源回收

如果類中存在多個測試方法,那麼測試執行順序為

1.1setUp->
    1.2test_測試方法1->
    1.3tearDown->
    1.4setUp->
    1.5test_測試方法2->
    1.6tearDown->      

4.TestCase

4.1 測試異常

測試的時候遇到異常可以通過在方法後面throws Exception處理,将異常抛出,在最終的測試結果中可以檢視到。

那麼什麼時候需要抛出異常呢?

下面我舉一個場景:

實際開發過程中,我們難免會設計一些方法,這些方法可能會抛出某些指定的異常,需要給上層使用者進行處理,那麼在測試的時候,我們可以将這些指定的異常進行捕捉,然後針對其他異常進行抛出,作為測試結果,測試這些方法是否會有額外的異常出現。

例如下面的例子:

public class MathUtil {

    /**
     * 從一個浮點型字元串中擷取小數部分的整數
     * <p/>
     * 實際上如果是一個整數或者其他不是數字的字元串,我們除了抛出無法轉型的異常之外,還可能會抛出數組越界的異常
     * 假設是"123",那麼是沒有numbers[1]的
     *
     * @param str
     * @return
     * @throws NumberFormatException
     */
    public static int getDecimalFromString(String str) throws NumberFormatException {//聲明已經知道的異常
        String[] numbers = str.split("\\.");
        return Integer.valueOf(numbers[1]);
    }

}
測試類      
public class MathUtilJunit3TestCase extends TestCase {


    public void test_getDecimalFromString() throws Exception {
        System.out.println("---Calling test_getDecimalFromString---");
        try {
            assertEquals(456, MathUtil.getDecimalFromString("123.456"));
            assertEquals(0, MathUtil.getDecimalFromString("abc"));
            assertEquals(0, MathUtil.getDecimalFromString("123"));
        } catch (NumberFormatException e) {
            assertNotNull(e.getMessage());
        }
    }
}
運作結果片段,除了定義的格式異常,還會出現 OutOfBoundsException 等其它提前沒有預料到的異常      
Android單元測試系列

經過這個測試能夠過濾已知異常,對未知異常暴露在測試階段。

4.2 測試套件

測試套件說白了就是批量測試。将獨立的測試進行組裝,達到一次測試多個目的。

/**
 * @author ywc
 * @since 2017-01-13 
 */
public class UtilTestSuite extends TestSuite {

    public UtilTestSuite() {
        super();
        addTestSuite(MathUtilTestCase.class);
    }
}      

通過junit提供的api可以友善的實作。需要注意繼承的父類是TestSuit 而不是單元測試TestCase。

4.3 測試

配置全局初始化和結束

TestSuite可以了解為一個功能單元集合,有時我們希望在測試這個單元功能時,全局初始化一些資源,以及全局回收一些資源(比如:初始化時建立資料庫連接配接,結束時候統一結束連接配接),那麼這個時候,采用TestCase的setUp和tearDown明顯不夠用了(testcase的setup和down是每次運作單個測試方法均會調用)

public class UtilTestSuite extends TestSuite {

    public UtilTestSuite() {
        super();
        addTestSuite(MathUtilTestCase.class);
    }

    public Test suite() {

        addTestSuite(MathUtilTestCase.class);


        TestSetup wrapper = new TestSetup(this) {
            protected void setUp() {
                System.out.println("---Calling Global_setUp---");
            }

            protected void tearDown() {
                System.out.println("---Calling Global_tearDown---");
            }
        };
        return wrapper;

    }      
Android單元測試系列

如果你進行過實際操作的話,就會發現預設的AndroidSDK中沒有TestSetup類,這是因為Android SDK中僅保留極少部分的Junit3代碼(主要是junit.framework的代碼),其中并沒有我們所用到的TestSetup類

那麼TestSetup類又是從哪裡來的呢,其實在使用的時候,我已經引用了Junit4.12的類庫了

Android單元測試系列