Android測試之旅之JUnit(二)

來源:互聯網
上載者:User

標籤:

開始

通過Android測試之旅之JUnit(一)的學習,我們對JUnit的知識有了初步的認識。聰明的你是不是發現其實並沒有你想象的那麼難呢?這章我們繼續來瞅瞅JUnit還有什麼好玩的。今天我們用一個簡單的例子給大家進行展示,方便更好的理解。

Parameterized

我們先來看下面一個待測試類別PrettyTest:

public class PrettyTest {    /**     * 根據輸入值的大小返回字串     * @param a 輸入值     * @return 返回的字串結果     */    public String print(int a){        System.out.println("==========current input number is: " + a + "==========");        return  a > 0? "大":"小";    }}

這個類相當的純潔。如果你看過上一章的內容,機智的你一定可以很快的寫出測試案例PrettyTest1:

public class PrettyTest1 {    private static PrettyTest mTest;    private static String expectedStrAbove;    private static String expectedStrBelow;    @BeforeClass    public static void create(){        mTest = new PrettyTest();        expectedStrAbove = "大";        expectedStrBelow = "小";    }    @Test    public void testPrintAbove(){        int i = 1;        String resultStr = mTest.print(i);        System.out.println("==========testPrintBelow result string is:"+ resultStr + "==========");        Assert.assertEquals(expectedStrAbove,resultStr);        Assert.assertNotEquals(expectedStrBelow,resultStr);    }    @Test    public void testPrintBelow(){        int i = -1;        String resultStr = mTest.print(i);        System.out.println("==========testPrintBelow result string is:"+ resultStr + "==========");        Assert.assertEquals(expectedStrBelow,resultStr);        Assert.assertNotEquals(expectedStrAbove,resultStr);    }}

仔細看看,很滿意,很傲嬌。但是,有個小問題,如果我們要用多個值來測試怎麼辦?這裡只列舉了大於0和小於0的兩種情況。而在實際的開發中,一個方法中有的時候可能會有n多種情況。這個時候,Parameterized類的作用就能體現出來了。還是針對於PrettyTest,我麼來看看PrettyTest2這個測試案例:

@RunWith(Parameterized.class)public class PrettyTest2 {    //-------初始化代碼省略-------    @Parameterized.Parameter    public int testNum;    @Parameterized.Parameters    public static Collection<Integer> initData() {        List<Integer> data = new ArrayList<>();        data.add(-1);        data.add(0);        data.add(1);        return data;    }    @Test    public void test(){        String resultStr = mTest.print(testNum);        System.out.println("==========testPrintBelow result string is:"+ resultStr + "==========");        if (testNum > 0){            //-------判斷是否與預期值相同-------        }else{            //-------判斷是否與預期值相同-------        }    }}

代碼確實沒有少多少,我們再來看下運行結果。

運行了三次,把我們在initData方法中設定的資料都跑了一遍。然後test方法中隊各種情況進行相應的判斷,是不是覺得這樣效率提高了不少。其中@Parameter註解可以設定需要測試的公開變數,而@Parameters註解則是設定一個裝滿測試資料的集合。如果你不想使用@Parameter註解,還可以通過建構函式來設定。代碼如下:

    private int testNum;    public PrettyTest2(int num){        this.testNum = num;    }

測試結果和之前的測試一模一樣。

RulesJUnit

稍微回味一下,我們繼續探索。Rules註解是個非常有意思註解,我們可以通過該註解在測試案例中類比我們需要的行為,聽這話有點昏昏的,別急,繼續往下看。因為測試的情境有很多,JUnit為我們定義了很多非常有用的Rules。比如說TemporaryFolder這個類,這個類就是JUnit為我們提供在測試過程中建立檔案夾的類,當測試結束之後,檔案夾會自動刪除。上代碼:

public class RuleTester {    private static File testFile = null;    @Rule    public TemporaryFolder mFolder = new TemporaryFolder();    @Before    public void before(){        System.out.println("----------method before testFile is: "+ testFile + "----------");        Assert.assertNull(testFile);    }    @Test    public void test(){        try {            testFile = mFolder.newFile("myfile.txt");            boolean flag = testFile.exists();            System.out.println("----------method test testFile exists flag: "+ flag + "----------");            Assert.assertTrue(flag);        } catch (IOException e) {            Assert.fail("exception is:"+e.getMessage());        }    }    @AfterClass    public static void after(){        boolean flag = testFile.exists();        System.out.println("----------method after testFile exists flag: "+ flag + "----------");        Assert.assertFalse(flag);    }}

先看下顯示結果。

事實證明確實在測試方法的過程中建立過一個檔案,並且在測試案例結束的時候檔案被刪除了。是不是很神奇?很溜?當然,如果你有興趣一步步的跟進去看源碼,你就會發現這其實就是對一個檔案建立,使用以及刪除的一個過程。TemporaryFolder類繼承了ExternalResource類,而ExternalResource類實現了介面TestRule中的apply方法。這裡不貼代碼是不是有點繞,別急,我們先繼續往下走,走完再來回頭看。

自訂

上面提到了TestRule這個神奇的介面,我打算寫一個內建日誌列印的Rule,裡麵包含一個列印訊息的方法。在控制台可以看到Rule被調用的過程。好,開始行動!

public class LogRule implements TestRule{    private Statement mBase;    @Override    public Statement apply(Statement base, Description description) {        this.mBase = base;        return new LogStatement(base);    }    public void print(String message){        System.out.println("LogRule message is:" + message);    }    public class LogStatement extends Statement{        private final Statement base;        public LogStatement(Statement base) {            this.base = base;        }        @Override        public void evaluate() throws Throwable {            System.out.println("method evaluate before");            try{                base.evaluate();            }finally {                System.out.println("method evaluate after");            }        }    }}

在這個自訂的Rule中,我們重寫了apply方法,添加了print方法,並且重寫了Statement類中的evaluate方法,在這個方法前後我們加了日誌的列印。下面來看下在測試案例中的調用和輸出結果。

public class LogRuleTest {    @Rule    public LogRule mLogRule= new LogRule();    @Test    public void test(){        String message = "method test";        mLogRule.print(message);    }}


調用是不是很方便,現在在回頭看看之前我們講到的檔案建立,使用和刪除的過程,是不是一下子就恍然大悟了。那句俗話怎麼說的,車到山前必有路,船到橋頭自然直。

Categories

看到這裡有點累了吧,別急,快結束了。在上篇我們介紹過了SuiteClasses來選擇需要測試的測試案例。而Categories這個註解則可以幫你更上一層樓。為什麼這麼說呢,因為這個註解可以給你測試案例中的測試方法進行歸類。閑話不多說,上代碼!

public class ICategories {    public interface First {    }    public interface Second {    }}
public class CategoriesA {    @Test    public void a() {        System.out.println("------class CategoriesA method a called------");    }    @Category(ICategories.First.class)    @Test    public void b() {        System.out.println("------class CategoriesA method b called------");    }}
@Category({ ICategories.First.class, ICategories.Second.class })public class CategoriesB {    @Test    public void c() {        System.out.println("------class CategoriesB method c called------");    }}

有三個檔案,希望大家不要看暈了。我們首先定義兩種測試的類型,分別是介面First和Second。然後通過註解@Category對不同測試案例中的不同方法進行標註,最後選擇自己需要測試的內容。其中測試類別CategoriesAa方法沒有任何標誌,b方法註明了First介面。CategoriesB測試案例上註明了FirstSecond兩個介面。我們接著往下看:

@RunWith(Categories.class)@Categories.IncludeCategory(ICategories.First.class)@Categories.ExcludeCategory(ICategories.Second.class)@Suite.SuiteClasses({ CategoriesA.class, CategoriesB.class })public class CategoriesTest {}

我們運行CategoriesTest這個測試案例。結果如下:

僅僅運行了CategoriesAb方法,想必聰明的你已經知道了,@IncludeCategory註解表示我們需要包含哪個介面,@ExcludeCategory註解則表示我們剔除哪些介面。所以包含First介面而不包含Second介面的方法只有CategoriesAb方法。好啦!你可以邊回味今天的知識邊休息啦。

結尾

到這裡,我們Android測試之旅之JUnit的全部內容就已經結束啦。不知道這些內容是否可以協助您解決問題。當然,有什麼問題可以隨時留言,我一定會積極回答的。

Android測試之旅之JUnit(二)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.