博客源址:http://kikujiang.com/2016/05/07/android-test-junit-160508/
开始
通过Android测试之旅之JUnit(一)的学习,我们对JUnit的知识有了初步的认识。聪明的你是不是发现其实并没有你想象的那么难呢?这章我们继续来瞅瞅JUnit还有什么好玩的。今天我们用一个简单的例子给大家进行展示,方便更好的理解。
Parameterized
我们先来看下面一个待测试类PrettyTest
:
1 2 3 4 5 6 7 8 9 10 11 | public class PrettyTest { /** * 根据输入值的大小返回字符串 * @param a 输入值 * @return 返回的字符串结果 */ public String print(int a){ System.out.println("==========current input number is: " + a + "=========="); return a > 0? "大":"小"; } } |
这个类相当的纯洁。如果你看过上一章的内容,机智的你一定可以很快的写出测试用例PrettyTest1
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public class PrettyTest1 { private static PrettyTest mTest; private static String expectedStrAbove; private static String expectedStrBelow; public static void create(){ mTest = new PrettyTest(); expectedStrAbove = "大"; expectedStrBelow = "小"; } 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); } 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
这个测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | (Parameterized.class)public class PrettyTest2 { //-------初始化代码省略------- .Parameter public int testNum; Parameters public static Collection<Integer> initData() { . List<Integer> data = new ArrayList<>(); data.add(-1); data.add(0); data.add(1); return data; } 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
注解,还可以通过构造函数来设置。代码如下:
1 2 3 4 | private int testNum; public PrettyTest2(int num){ this.testNum = num; } |
测试结果和之前的测试一模一样。
Rules
JUnit
稍微回味一下,我们继续探索。Rules
注解是个非常有意思注解,我们可以通过该注解在测试用例中模拟我们需要的行为,听这话有点昏昏的,别急,继续往下看。因为测试的场景有很多,JUnit
为我们定义了很多非常有用的Rules
。比如说TemporaryFolder
这个类,这个类就是JUnit
为我们提供在测试过程中创建文件夹的类,当测试结束之后,文件夹会自动删除。上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class RuleTester { private static File testFile = null; public TemporaryFolder mFolder = new TemporaryFolder(); public void before(){ System.out.println("----------method before testFile is: "+ testFile + "----------"); Assert.assertNull(testFile); } 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()); } } 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
被调用的过程。好,开始行动!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public class LogRule implements TestRule{ private Statement mBase; 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; } 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
方法,在这个方法前后我们加了日志的打印。下面来看下在测试用例中的调用和输出结果。
1 2 3 4 5 6 7 8 9 10 11 | public class LogRuleTest { public LogRule mLogRule= new LogRule(); public void test(){ String message = "method test"; mLogRule.print(message); } } |
调用是不是很方便,现在在回头看看之前我们讲到的文件创建,使用和删除的过程,是不是一下子就恍然大悟了。那句俗话怎么说的,车到山前必有路,船到桥头自然直。
Categories
看到这里有点累了吧,别急,快结束了。在上篇我们介绍过了SuiteClasses
来选择需要测试的测试用例。而Categories
这个注解则可以帮你更上一层楼。为什么这么说呢,因为这个注解可以给你测试用例中的测试方法进行归类。闲话不多说,上代码!
1 2 3 4 5 6 7 8 | public class ICategories { public interface First { } public interface Second { } } |
1 2 3 4 5 6 7 8 9 10 11 12 | public class CategoriesA { public void a() { System.out.println("------class CategoriesA method a called------"); } (ICategories.First.class) public void b() { System.out.println("------class CategoriesA method b called------"); } } |
1 2 3 4 5 6 7 | ({ ICategories.First.class, ICategories.Second.class })public class CategoriesB { public void c() { System.out.println("------class CategoriesB method c called------"); } } |
有三个文件,希望大家不要看晕了。我们首先定义两种测试的类型,分别是接口First和Second。然后通过注解@Category
对不同测试用例中的不同方法进行标注,最后选择自己需要测试的内容。其中测试类CategoriesA
的a
方法没有任何标志,b
方法注明了First
接口。CategoriesB
测试用例上注明了First
和Second
两个接口。我们接着往下看:
1 2 3 4 5 6 7 | (Categories.class) .IncludeCategory(ICategories.First.class) .ExcludeCategory(ICategories.Second.class) .SuiteClasses({ CategoriesA.class, CategoriesB.class })public class CategoriesTest { } |
我们运行CategoriesTest
这个测试用例。结果如下:
仅仅运行了CategoriesA
的b
方法,想必聪明的你已经知道了,@IncludeCategory
注解表示我们需要包含哪个接口,@ExcludeCategory
注解则表示我们剔除哪些接口。所以包含First
接口而不包含Second
接口的方法只有CategoriesA
的b
方法。好啦!你可以边回味今天的知识边休息啦。
结尾
到这里,我们Android测试之旅之JUnit的全部内容就已经结束啦。下面菜主要好好研究Android相关方面的测试啦。