总结一下JUnit4中常用的注解:
1.@RunWith:一个类添加@RunWith或继承的父类添加@RunWith时,JUnit会调用@RunWith使用指定的自定义Runner来执行该类中的测试方法,而不是JUnit4中固定的Runner。
Runner就是用来执行测试用例并通知给RunNotifier执行测试用例的进展。
JUnit4默认的Runner为BlockJUnit4ClassRunner,当你在Eclipse中新建一个JUnit Test Case时,生成的class并未显示指定@RunWith,这时Runner为默认的BlockJUnit4ClassRunner。
java.lang.Object org.junit.runner.Runner org.junit.runners.ParentRunner<FrameworkMethod> org.junit.runners.BlockJUnit4ClassRunner
常见的Runner有4类:
(1).Suite:执行指定多个类的测试方法。
java.lang.Object org.junit.runner.Runner org.junit.runners.ParentRunner<Runner> org.junit.runners.Suite
如下,运行SuiteClassTest,会执行聚合ATest.class和BTest.class中所有的测试方法。
@RunWith(Suite.class)
@SuiteClasses({ATest.class, BTest.class})
public class SuiteClassTest{
}
(2).Parameterized:执行参数化测试。
java.lang.Object org.junit.runner.Runner org.junit.runners.ParentRunner<Runner> org.junit.runners.Suite org.junit.runners.Parameterized
(3).Theories:根据@DataPoint作为输入数据,执行测试方法。
java.lang.Object org.junit.runner.Runner org.junit.runners.ParentRunner<FrameworkMethod> org.junit.runners.BlockJUnit4ClassRunner org.junit.experimental.theories.Theories
(4).Categories:执行@IncludeCategory或其子类型的测试方法或类。
java.lang.Object org.junit.runner.Runner org.junit.runners.ParentRunner<Runner> org.junit.runners.Suite org.junit.experimental.categories.Categories
当然,还可以自定义Runner:
(5)RetryRunner:重试机制,淘测试中一篇文章:http://www.taobaotest.com/blogs/2373。
(6)ConcurrentSuite:使用线程池并发执行测试用例,另写文章介绍JUnit4的并发执行。
2.@Test:标记为测试方法。
注解成员有:(1)timeout=100ms,超时验证 (2)expected=异常class,抛出异常验证
3.@Ignore:忽略此测试方法。
4.@BeforeClass,在开始执行整个类的测试方法前,先执行一次该方法。申请资源等。
@AfterClass,在执行完整个类的测试方法后,执行一次该方法。释放资源等。
@Before,在执行整个类的每个测试方法前,执行一次该方法。
@After,在执行完整个类的每个测试方法后,执行一次该方法。
5.@FixMethodOrder,指定测试方法的顺序,
比如:@FixMethodOrder(MethodSorters.NAME_ASCENDING), 以方法名的字典序执行。MethodSortersm枚举类型:
DEFAULT Sorts the test methods in a deterministic, but not predictable, order |
JVM Leaves the test methods in the order returned by the JVM. |
NAME_ASCENDING Sorts the test methods by the method name, in lexicographic order, with Method.toString() used as a tiebreaker |
理论介绍完了,下面用实例来实践下。
1.被测类 Calculator.java
public class Calculator { public double add(double num1, double num2) { return num1 + num2; } public double minus(double num1, double num2) { return num1 - num2; } public double multiply(double num1, double num2) { // 死循环,模拟超时 int i = 0; while (true) { i++; } } public double division(double num1, double num2) { if(0.0 == num2){ throw new ArithmeticException("被除数不能为0"); }else{ return num1 / num2; } } }
package com.junit.annotest; import static org.junit.Assert.*; import static org.hamcrest.Matchers.*; import java.util.ArrayList; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; public class CalculatorTest { public interface SmokeTests{ } public interface SlowTests{ } @BeforeClass public static void setUpBeforeClass() throws Exception { System.out.println("BeforeClass"); } @AfterClass public static void tearDownAfterClass() throws Exception { System.out.println("AfterClass"); } @Before public void setUp() throws Exception { System.out.println("Before"); } @After public void tearDown() throws Exception { System.out.println("After"); } public CalculatorTest(){ System.out.println("无参构造函数"); } @Category(SmokeTests.class) @Test public void testAdd1() { assertThat(3.64, is(new Calculator().add(3.14, 0.5))); } @Category(SlowTests.class) @Test public void testAdd2() throws Exception { Thread.sleep(1000); assertThat(1003.14, is(new Calculator().add(3.14, 1000))); } @Category(SlowTests.class) @Test public void testAdd3() throws Exception { Thread.sleep(2000); assertThat(2003.14, is(new Calculator().add(3.14, 2000))); } @Ignore @Test public void testMinus() { assertThat(0.0, is(new Calculator().minus(3.14, 3.14))); } @Test(timeout=1000) public void testMultiply() { assertThat(3.14, is(new Calculator().multiply(3.14, 1.0))); } @Test(expected=ArithmeticException.class) public void testDivision() { new Calculator().division(3.14, 0.0); } }
BeforeClass
无参构造函数
Before
After
无参构造函数
Before
After
无参构造函数
Before
After
无参构造函数
Before
After
无参构造函数
Before
After
AfterClass
testMultiply测试方法使用了@test(timeout=1000), 如果方法执行时间超过1000ms, 则该测试方法执行为Errors。
(二)CategoriesTest.java 使用了Categories Runner,执行分类的用例;@SuiteClasses指定特定的测试类;@IncludeCategory指定执行被标记分类(@Category(标记分类名.class))的测试类或方法。如下,
@IncludeCategory(SmokeTests.class)只运行
CalculatorTest.class中被标记为SmokeTests的测试方法:testAdd1(); @ExcludeCategory 不执行测试类或方法。
package com.junit.annotest; import static org.junit.Assert.*; import org.junit.AfterClass; import org.junit.Test; import org.junit.experimental.categories.Categories; import org.junit.experimental.categories.Categories.IncludeCategory; import org.junit.runner.RunWith; import org.junit.runners.Suite.SuiteClasses; import com.junit.annotest.CalculatorTest.SmokeTests; @RunWith(Categories.class) @SuiteClasses(CalculatorTest.class) @IncludeCategory(SmokeTests.class) public class CategoriesTest { }
2. Runner: Parameterized,参数化执行用例。
被测类:Fibonacci.java
package com.junit.annotest; public class Fibonacci { // 根据index,获取Fibonacci数列的值 public int valueOfFib(int index){ if(0 == index){ return 0; }else if(1 == index){ return 1; }else{ return valueOfFib(index-2) + valueOfFib(index-1); } } }
@Parameters指定数据集,该注解下有个name成员,可以标注每个数据集成员的信息,index所在数据集索引,{n}每个数据集元素{...}的第n+1的值。被注解的方法返回数据集数组。运行测试方法时,通过带参构造函数,生成FibonacciTest实例,获取数据集成员,一组数据集对应执行一次。
package com.junit.annotest; import static org.junit.Assert.*; import static org.hamcrest.Matchers.*; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class FibonacciTest { @Parameters(name="{index}:fib[{0}]={1}") public static List<Object[]> data() { return Arrays.asList( new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 8, 21 } }); } private int index; private int value; public FibonacciTest(int index, int value) { super(); this.index = index; this.value = value; } @Test public void testFib() { assertThat(value, is(new Fibonacci().valueOfFib(index))); } }运行结果:
(二)使用@Parameter(n)获取数据集
注意,这时类数据成员为public访问类型,并为数据成员指定@parameter(n),n表示该成员获取数据集中元素第n个值。
package com.junit.annotest; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import java.util.Arrays; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class FibonacciTest2 { @Parameters(name="{index}:fib[{0}]={1}") public static List<Object[]> data(){ return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 8, 21 } }); } @Parameter(0) public int index; @Parameter(1) public int value; @Test public void testFib() { assertThat(value, is(new Fibonacci().valueOfFib(index))); } }运行结果:同上图。
3.Runner: Theories 通过@DataPoint(单个),@DataPoints(数组)指定数据集;@Theory指定测试方法,该方法带形参,获取前面@DataPoint或@DataPoints指定的数据。适合使用大量数据,进行测试。
package com.junit.annotest; import static org.junit.Assert.*; import static org.hamcrest.Matchers.*; import org.junit.Test; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; @RunWith(Theories.class) public class TheoriesTest { @DataPoint public static int num1 = 2; @DataPoint public static int num2 = 8; @DataPoints public static int[] num3 = {4, 5, 6, 7, 9}; @Theory public void testFibon(int num) { System.out.println(num); assertThat(num,greaterThan(0)); } }测试结果如下: