在很多地方无法完全用中文来描述,所以有些地方还需英文来描述。
本篇注重概念内容,为后面的测试案例做铺垫
定义测试方法
JUnit使用注解标注为测试方法并配置它们,下表中给出了JUnit4非常重要的注解。下面所有的注解都用在方法上。
断言语句(Assert statements)
JUnit提供静态方法,通过Assert类来测试某些条件。这些断言语句通常以assert开头。他们允许你指定错误信息、预期结果和实际结果。断言方法将测试返回的实际值和预期值相比较。如果比较失败就会抛出AssertionException异常。
下表简单的介绍了这些方法。[]中的参数是可选的字符串类型。
JUnit 组合测试(JUnit test suites)
如果你有几个测试类,那么可以使用组合测试。这样在运行时组合测试将会按照顺序执行所有这个组合测试中的测试类。另外组合测试还可以包含其他的组合测试。(呃。。。有些绕)。简单的说就是它可以一次性执行多个测试用例。
下面的例子演示了组合测试的用法。它包含了两个测试类MyClassTest和CalculatorTest。如果继续想添加测试类继续放在@SuiteClasses注解中即可。
package com.lulu.androidtestdemo; import org.junit.runner.RunWith; import org.junit.runners.Suite; /** * Created by zhanglulu on 2018/1/24. */ @RunWith(Suite.class) @Suite.SuiteClasses({ MyClassTest.class,CalculatorTest.class }) public class AllTest { } |
禁用测试
在上文中提到可以使用@ignore注解来标记禁用当前测试方法。或者也可以使用Assume.assumeFalse或Assume.assumeTrue来判断测试条件。Assume.assumeFalse方法的测试条件返回true则表示当前测试方法无效,同理Assume.assumeTrue的测试条件返回false表示当前测试方法无效。
下图中示例就是在Windows系统中禁用addition_isCorrect()方法。其中System.getProperty("os.name").contains("Windows")称之为测试条件。
package com.lulu.androidtestdemo; import org.junit.Assume; import org.junit.Test; import static org.junit.Assert.assertEquals; /** *禁用测试 */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { Assume.assumeFalse(System.getProperty("os.name").contains("Windows")); assertEquals(4, 2 + 2); } } |
参数化测试(Parameterized test)
JUnit可以在测试类使用参数进行测试。这个类包含一个待测试的方法,并且这个方法可以用不同的参数去执行。
要想将测试类标记为参数化测试,必须使用注解:@RunWith(Parameterized.class)
这样的测试类必须包含一个静态方法,这个方法要使用@Parameters注解标注。而且这个方法要生成并返回一个数组的集合(对,没错,是数组的集合Collection<Object[]>),集合中的每项都用作测试方法的参数。
你可以使用 @Parameter()注解在公共字段中标注测试值,用来做字段的缺省值。
下面是参数化测试的示例。
/** * Created by zhanglulu on 2018/1/24. * 参数化测试示例 */ @RunWith(Parameterized.class) public class ParameterizedTestFields { @Parameterized.Parameter(0) public int m1; @Parameterized.Parameter(1) public int m2; @Parameterized.Parameter(2) public int result; // creates the test data @Parameterized.Parameters public static Collection<Object[]> data() { Object[][] data = new Object[][] { { 1 , 2, 2 }, { 5, 3, 15 }, { 121, 4, 484 } }; return Arrays.asList(data); } @Test public void testMultiplyException() { MyClass tester = new MyClass(); assertEquals("Result", result, tester.multiply(m1, m2)); } } |
Note: 必须提供@Parameter方法,方法的返回必须是public static Collection,不能有参数,并且collection元素必须是相同长度的数组。同时数组的长度必须与测试类的字段(m1,m2,result)的数量相匹配。
如果不使用 @Parameter()标注公共字段,也可以使用构造方法给字段赋值,如代码所示:
/** * Created by zhanglulu on 2018/1/24. * 参数化测试示例 */ @RunWith(Parameterized.class) public class ParameterizedTestFields { public int m1; public int m2; public int result; public ParameterizedTestFields(int m1, int m2, int result) { this.m1 = m1; this.m2 = m2; this.result = result; } // creates the test data @Parameterized.Parameters public static Collection<Object[]> data() { Object[][] data = new Object[][] { { 1 , 2, 2 }, { 5, 3, 15 }, { 121, 4, 484 } }; return Arrays.asList(data); } @Test public void testMultiplyException() { MyClass tester = new MyClass(); assertEquals("Result", result, tester.multiply(m1, m2)); } } |
Note : 需要注意的是两者必须有其一,否则会抛出反射参数不匹配的异常:java.lang.IllegalArgumentException: wrong number of arguments
还有其他的实现方案,这里不再详述请移步:https://github.com/Pragmatists/JUnitParams.
分类测试(Category)
Category继承自Suit,可以让我们的测试类中的测试方法进行分类测试,下面的例子就介绍了如何使用Category快速的进行分类测试。
public class A { @Test public void a() { fail(); } @Category(SlowTests.class) @Test public void b() { } } @Category({ SlowTests.class, FastTests.class }) public class B { @Test public void c() { } } public interface FastTests { } public interface SlowTests { } |
进行分类测试:
@RunWith(Categories.class) @Categories.IncludeCategory(SlowTests.class) @Suite.SuiteClasses({ A.class, B.class }) public class SlowTestSuite { } |
JUnit 规则 (JUnit Rule)
简介
Rule是JUnit4的新特性,它可以让我们扩展JUnit的功能,灵活地改变测试方法的行为。JUnit中使用@Rule和@ClassRule两个注解来实现Rule的扩展,这两个注解需要放在实现了TestRule接口的成员变量(@Rule)或者静态变量(@ClassRule)上。@Rule和@ClassRule的不同点是,@Rule是方法级别的,每个测试方法执行时都会调用被注解的Rule,而@ClassRule是类级别的,在执行一个测试类的时候只会调用一次被注解的Rule。
JUnit内置的Rule
ExpectedException
例如下面的示例,用来检测抛出的异常信息是否符合预期。当methodToBeTest方法中抛出IllegalArgumentException异常,并且异常信息中含有“Negative value not allowed”信息时,测试通过。
package com.lulu.androidtestdemo.junit.rule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; /** * Created by zhanglulu on 2018/1/24. * JUnit Rules */ public class RuleExceptionTesterExample { @Rule public ExpectedException exception = ExpectedException.none(); @Test public void throwsIllegalArgumentExceptionIfIconIsNull() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Negative value not allowed"); ClassToBeTested t = new ClassToBeTested(); t.methodToBeTest(-1); } } class ClassToBeTested { public void methodToBeTest(int i) { if (i == -1) { throw new IllegalArgumentException("Negative value not allowed"); } } } |
TemporaryFolder
TemporaryFolder 类可以在测试之前创建临时的文件或文件夹,并且在测试结束后自动删除。
package com.lulu.androidtestdemo.junit.rule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.IOException; import static org.junit.Assert.assertTrue; /** * Created by zhanglulu on 2018/1/24. * testUsingTempFolder */ public class RuleTester { @Rule public TemporaryFolder folder = new TemporaryFolder(); @Test public void testUsingTempFolder() throws IOException { File createdFolder = folder.newFolder("newfolder"); File createdFile = folder.newFile("myfilefile.txt"); assertTrue(createdFile.exists()); assertTrue(createdFolder.exists()); } } |
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。