Junit 4

【转】Junit4详解一:Junit总体介绍

转自http://www.cnblogs.com/caoyuanzhanlang/p/3534846.html

    Junit是一个可编写重复测试的简单框架,是基于Xunit架构的单元测试框架的实例。Junit4最大的改进是大量使用注解(元数据),很多实际执行 过程都在Junit的后台做完了,而且写test case 的类不需要继承TestCase,只需要在所要做test case的方法前加@Test 注解即可。

如:

复制代码
1 import static org.junit.Assert.*;
2 2 public class TestCaculatorClass { 3 3 @Test 4 4 public void test() throws IOException, RuntimeException{ 5 5 CaculatorClassForTest cal = new CaculatorClassForTest(); 6 6 assertEquals(30, cal.sum(10, 20)); 7 7 } 8 8 }
复制代码

直接点击右键,run as... Junit Test即可运行此test case。

Assert类里面有很多assert方法,包括:assertEquals(), assertNotNull(),assertTtrue(),assertFalse(),assertThat()等,其中assertThat用的是match的形式。

因此,Junit提供很多中Match,其中CoreMatchers是其中一个比较完善的实现类。具体有上面方法可以查阅CoreMatchers类。

复制代码
 1 import static org.hamcrest.CoreMatchers.allOf;
 2 import static org.hamcrest.CoreMatchers.anyOf;  3 import static org.hamcrest.CoreMatchers.equalTo;  4 import static org.hamcrest.CoreMatchers.not;  5 import static org.hamcrest.CoreMatchers.sameInstance;  6 import static org.hamcrest.CoreMatchers.startsWith;  7 import static org.junit.Assert.assertThat;  8 import static org.junit.matchers.JUnitMatchers.both;  9 import static org.junit.matchers.JUnitMatchers.containsString; 10 import static org.junit.matchers.JUnitMatchers.everyItem; 11 import static org.junit.matchers.JUnitMatchers.hasItems; 12 13 import java.util.Arrays; 14 15 import org.hamcrest.core.CombinableMatcher; 16 import org.junit.Test; 17 18 public class AssertTests { 19  @Test 20 public void testAssertArrayEquals() { 21 byte[] expected = "trial".getBytes(); 22 byte[] actual = "trial".getBytes(); 23 org.junit.Assert.assertArrayEquals("failure - byte arrays not same", expected, actual); 24  } 25 26  @Test 27 public void testAssertEquals() { 28 org.junit.Assert.assertEquals("failure - strings not same", 5l, 5l); 29  } 30 31  @Test 32 public void testAssertFalse() { 33 org.junit.Assert.assertFalse("failure - should be false", false); 34  } 35 36  @Test 37 public void testAssertNotNull() { 38 org.junit.Assert.assertNotNull("should not be null", new Object()); 39  } 40 41  @Test 42 public void testAssertNotSame() { 43 org.junit.Assert.assertNotSame("should not be same Object", new Object(), new Object()); 44  } 45 46  @Test 47 public void testAssertNull() { 48 org.junit.Assert.assertNull("should be null", null); 49  } 50 51  @Test 52 public void testAssertSame() { 53 Integer aNumber = Integer.valueOf(768); 54 org.junit.Assert.assertSame("should be same", aNumber, aNumber); 55  } 56 57 // JUnit Matchers assertThat 58  @Test 59 public void testAssertThatBothContainsString() { 60 org.junit.Assert.assertThat("albumen", both(containsString("a")).and(containsString("b"))); 61  } 62 63  @Test 64 public void testAssertThathasItemsContainsString() { 65 org.junit.Assert.assertThat(Arrays.asList("one", "two", "three"), hasItems("one", "three")); 66  } 67 68  @Test 69 public void testAssertThatEveryItemContainsString() { 70 org.junit.Assert.assertThat(Arrays.asList(new String[] { "fun", "ban", "net" }), everyItem(containsString("n"))); 71  } 72 73 // Core Hamcrest Matchers with assertThat 74  @Test 75 public void testAssertThatHamcrestCoreMatchers() { 76 assertThat("good", allOf(equalTo("good"), startsWith("good"))); 77 assertThat("good", not(allOf(equalTo("bad"), equalTo("good")))); 78 assertThat("good", anyOf(equalTo("bad"), equalTo("good"))); 79 assertThat(7, not(CombinableMatcher.<Integer> either(equalTo(3)).or(equalTo(4)))); 80 assertThat(new Object(), not(sameInstance(new Object()))); 81 } 82 83 @Test 84 public void testAssertTrue() { 85 org.junit.Assert.assertTrue("failure - should be true", true); 86 } 87 }
复制代码

问题一,我可不可以把多个测试类放在一起执行?

回答: 可以。org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);利用这样,把test case 的类放进去,然后放在main()方法里执行。

问题二,@RunWith这个注解有什么作用?

回答:Junit4的默认runner为BlockJunit4ClassRunner,但是Junit4包括第三方软件还提供很多其他的runner,这样如果,我们想让我们的测试类用专门的runner来运行,这时候就可以用@RunWith(Suit.class

)标注测试类。其他特殊的runner有:

1. Suite: 字面理解是一个套装,通俗地讲,就是你可以把很多测试类放在一起,然后建一个类,标注为Suite.class,那么如果执行这个类,就会把所有的测试类一起执行。

复制代码
 1 import org.junit.runner.RunWith;
 2 import org.junit.runners.Suite;  3  4 @RunWith(Suite.class)  5 @Suite.SuiteClasses({  6 TestFeatureLogin.class,  7 TestFeatureLogout.class,  8 TestFeatureNavigate.class,  9 TestFeatureUpdate.class 10 }) 11 12 public class FeatureTestSuite { 13 // the class remains empty, 14 // used only as a holder for the above annotations 15 }
复制代码

 

2. Parameterized:根据所设计的参数来执行测试。假设我们要测试某一个方法,它有两个参数,每个参数需要设计不同值,那么我们最开始就是需要为 每个参数设计一个测试方法,这样就很麻烦,10种case就得10个方法,但是有了Parameterized runner,我们可以设计一个方法,多种参数来执行test case。

复制代码
 1 package com.citi.risk.core.test.impl;
 2 
 3 public class CaculatorClassForTest {  4  5 private int o1;  6 private int o2;  7 public int getO1() {  8 return this.o1;  9  } 10 public void setO1(int value) { 11 this.o1 = value; 12  } 13 public int getO2() { 14 return this.o2; 15  } 16 public void setO2(int value) { 17 this.o2 = value; 18  } 19 20 21 public CaculatorClassForTest() {} 22 public CaculatorClassForTest(int o1, int o2) { 23 this.o1 = o1; 24 this.o2 = o2; 25  } 26 27 public int sum(int o1, int o2){ 28 if(o1 > 200) { 29 throw new RuntimeException("o1 is too big"); 30  } 31 if(o2 > 200) { 32 throw new RuntimeException("o2 is too big"); 33  } 34 int sum; 35 sum = o1 + o2; 36 return sum; 37  } 38 }
复制代码

 

 

复制代码
 1 package com.citi.risk.core.test.impl;
 2 
 3 import static org.junit.Assert.*;  4  5 import java.io.IOException;  6 import java.util.List;  7  8 import org.junit.Rule;  9 import org.junit.Test; 10 import org.junit.rules.ExpectedException; 11 import org.junit.runner.RunWith; 12 import org.junit.runners.Parameterized; 13 import org.junit.runners.Parameterized.Parameter; 14 import org.junit.runners.Parameterized.Parameters; 15 16 import com.google.common.collect.Lists; 17 18 @RunWith(Parameterized.class) 19 public class TestCaculatorClass { 20  @Rule 21 public ExpectedException thrown = ExpectedException.none(); 22 23  @Parameters 24 public static List<Object[]> data() { 25 return Lists.asList(new Object[]{-1, 1, 0}, new Object[][]{{20, 20, 40},{30, 30, 60},{-5, -5, -10}}); 26  } 27 @Parameter(value = 0) 28 public int o1; 29 @Parameter(value = 1) 30 public int o2; 31 @Parameter(value = 2) 32 public int expector; 33 34  @Test 35 public void test() throws IOException, RuntimeException{ 36 CaculatorClassForTest cal = new CaculatorClassForTest(); 37  assertEquals(expector, cal.sum(o1, o2)); 38  } 39 40  @Test 41 public void testO1Exception(){ 42 CaculatorClassForTest cal = new CaculatorClassForTest(); 43 thrown.expect(RuntimeException.class); 44 thrown.expectMessage("o1 is too big"); 45 cal.sum(300, 100); 46  } 47  @Test 48 public void testO2Exception(){ 49 CaculatorClassForTest cal = new CaculatorClassForTest(); 50 thrown.expect(RuntimeException.class); 51 thrown.expectMessage("o2 is too big"); 52 cal.sum(100, 300); 53  } 54 55 }
复制代码

 

 以上两个类就是测试了Parameterized runner, 参数会自动匹配。它其实就是,看我们传入几种case, 也就是List.size(),然后,把类里面的方法,循环重复执行size()数目。

3. Categories:容易理解就是分类执行。假设我们有一种case: 我们写好了两个测试类,类A,类B,A有两个方法a(), b(),这时候我们有一个类来执行这两个类的test case,但是我们在类A里只想执行A.b(),但却不执行A.a(),这个时候我们可以用Categories runner。

复制代码
 1 public interface FastTests { /* category marker */ }  2 public interface SlowTests { /* category marker */ }  3  4 public class A {  5  @Test  6 public void a() {  7  fail();  8  }  9 10 @Category(SlowTests.class) 11  @Test 12 public void b() { 13  } 14 } 15 16 @Category({SlowTests.class, FastTests.class}) 17 public class B { 18  @Test 19 public void c() { 20 21  } 22 } 23 24 @RunWith(Categories.class) 25 @IncludeCategory(SlowTests.class) 26 @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite 27 public class SlowTestSuite { 28 // Will run A.b and B.c, but not A.a 29 } 30 31 @RunWith(Categories.class) 32 @IncludeCategory(SlowTests.class) 33 @ExcludeCategory(FastTests.class) 34 @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite 35 public class SlowTestSuite { 36 // Will run A.b, but not A.a or B.c 37 }
复制代码
 

4. Enclosed:如果我们把tests放在了内部类,这时候执行外部类是无法执行里面的test cases,这种情况下,就应该在outer class 用Enclosed runner。

要测试的类 Address:

复制代码
 1 package abstractions.domain;
 2 
 3     import java.io.Serializable;  4  5 import com.google.common.collect.ComparisonChain;  6  7 public class Address implements Serializable, Comparable<Address> {  8  9 private static final long serialVersionUID = 1L; 10 private final String address1; 11 private final String city; 12 private final String state; 13 private final String zip; 14 15 private Address(Builder builder) { 16 this.address1 = builder.address1; 17 this.city = builder.city; 18 this.state = builder.state; 19 this.zip = builder.zip; 20  } 21 22 public String getAddress1() { 23 return address1; 24  } 25 26 public String getCity() { 27 return city; 28  } 29 30 public String getState() { 31 return state; 32  } 33 34 public String getZip() { 35 return zip; 36  } 37 38  @Override 39 public int compareTo(Address that) { 40 return ComparisonChain.start().compare(this.zip, that.zip).compare(this.state, that.state) 41 .compare(this.city, that.city).compare(this.address1, that.address1).result(); 42  } 43 44  @Override 45 public boolean equals(Object obj) { 46 if (obj == null) { return false; } 47 if (getClass() != obj.getClass()) { return false; } 48 final Address that = (Address) obj; 49 50 return com.google.common.base.Objects.equal(this.address1, that.address1) 51 && com.google.common.base.Objects.equal(this.city, that.city) 52 && com.google.common.base.Objects.equal(this.state, that.state) 53 && com.google.common.base.Objects.equal(this.zip, that.zip); 54  } 55 56  @Override 57 public int hashCode() { 58 return com.google.common.base.Objects.hashCode(getAddress1(), getCity(), getCity(), getState(), getZip()); 59  } 60 61  @Override 62 public String toString() { 63 return com.google.common.base.Objects.toStringHelper(this).addValue(getAddress1()).addValue(getCity()).addValue(getState()).addValue(getZip()).toString(); 64  } 65 66 public static class Builder { 67 68 private String address1; 69 private String city; 70 private String state; 71 private String zip; 72 73 public Builder address1(String address1) { 74 this.address1 = address1; 75 return this; 76 } 77 78 public Address build() { 79 return new Address(this); 80 } 81 82 public Builder city(String city) { 83 this.city = city; 84 return this; 85 } 86 87 public Builder state(String state) { 88 this.state = state; 89 return this; 90 } 91 92 public Builder zip(String zip) { 93 this.zip = zip; 94 return this; 95 } 96 } 97 }
复制代码

test case:

复制代码
  1 package abstractions.domain;
  2 
  3     import static org.hamcrest.Matchers.is;  4 import static org.junit.Assert.assertThat;  5  6 import java.io.Serializable;  7  8 import org.junit.Before;  9 import org.junit.Test;  10 import org.junit.experimental.runners.Enclosed;  11 import org.junit.runner.RunWith;  12  13 import testhelpers.ComparabilityTestCase;  14 import testhelpers.EqualsHashCodeTestCase;  15 import testhelpers.SerializabilityTestCase;  16  17 /**  18  * The Class AddressTest.  19 */  20 @RunWith(Enclosed.class)  21 public class AddressTest {  22  23 /**  24  * The Class AddressComparabilityTest.  25 */  26 public static class AddressComparabilityTest extends ComparabilityTestCase<Address> {  27  28  @Override  29 protected Address createEqualInstance() throws Exception {  30 return new Address.Builder().address1("2802 South Havana Street").city("Aurora").state("CO").zip("80014").build();  31  }  32  33  @Override  34 protected Address createGreaterInstance() throws Exception {  35 return new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build();  36  }  37  38  @Override  39 protected Address createLessInstance() throws Exception {  40 return new Address.Builder().address1("14 Broad St").city("Nashua").state("NH").zip("03064").build();  41  }  42  }  43  44 /**  45  * The Class AddressEqualsHashCodeTest.  46 */  47 public static class AddressEqualsHashCodeTest extends EqualsHashCodeTestCase {  48  49  @Override  50 protected Address createInstance() throws Exception {  51 return new Address.Builder().address1("2802 South Havana Street").city("Aurora").state("CO").zip("80014").build();  52  }  53  54  @Override  55 protected Address createNotEqualInstance() throws Exception {  56 return new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build();  57  }  58  }  59  60 /**  61  * The Class AddressSerializabilityTest.  62 */  63 public static class AddressSerializabilityTest extends SerializabilityTestCase {  64  65  @Override  66 protected Serializable createInstance() throws Exception {  67 return new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build();  68  }  69  }  70  71 public static class AddressMiscTest {  72  73 private Address address;  74  75 /**  76  * Setup.  77  *  78  * @throws Exception the exception 79 */ 80 @Before 81 public void setUp() throws Exception { 82 address = new Address.Builder().address1("9839 Carlisle Boulevard NE").city("Albuquerque").state("NM").zip("87110").build(); 83 } 84 85 /** 86 * Test builder. 87 */ 88 @Test 89 public void testBuilder() { 90 assertThat(address.getAddress1(), is("9839 Carlisle Boulevard NE")); 91 assertThat(address.getCity(), is("Albuquerque")); 92 assertThat(address.getState(), is("NM")); 93 assertThat(address.getZip(), is("87110")); 94 } 95 96 @Test 97 public void testToString() { 98 assertThat(address.toString(), is("Address{9839 Carlisle Boulevard NE, Albuquerque, NM, 87110}")); 99 } 100 } 101 }
复制代码

问题三:不想执行某个类的test case 有什么方法?

回答: 用@Ignore, 如果要让某个类都不执行,@Ignore放在类里,如果不想执行某一个方法,只需要放在方法上。

复制代码
1 @Ignore
2 public class TestClass{ 3 4 @Ignore("Test is ignored as a demonstration") 5  @Test 6 public void testSane() { 7 assertThat(1, is(1)); 8  } 9 }
复制代码

问题四:某个test case执行时间太长,有什么办法终止?

回答: Junit4提供了timeout属性。

1 @Test(timeout=1000)
2 public void testWithTimeout() { 3  ... 4 }

 

Junit4还有更重要的@Rule 和 执行顺序。且听下回分解。

 

概要:

 

前一篇文章我们总体介绍了Junit4的用法以及一些简单的测试。之前我有个疑惑,Junit4怎么把一个test case跑起来的,在test case之前和之后我们能做些什么?

 

Junit4执行顺序是怎样的?带着这些问题,我写了这篇文章,仅供参考,不对之处,盼留言指正,感激万分。前一篇文章:【原创】Junit4详解一:Junit总体介绍

 

Junit4 runner总体介绍

 

Junit4编译器在执行TestCase的过 程中利用反射机制,以便我们可以对测试的开始过程中进行一些预处理,如读取元数据信息,拦截异常,数据库操作等,由于Junit4默认的测试执行器 是:BlockJUnit4ClassRunner,我们以这个执行器粗略地做一些研究。在TestCase执行过程中,主要用到以下 类,BlockJUnit4ClassRunner,ParentRunner,Statement,TestRule,Description,RunNotifier,InvokeMethod. 以下简单做些解释。

 

Junit4默认重要类简述,助于理解源代码

 

1. BlockJUnit4ClassRunner:Junit4的默认测试执行器,它有之前版本的runner同样的行为,也就兼容了之前的runner。但是它是基于Statement,实现更加简单,允许用户在执行工作流中某个合适的点插入用户新的操作, 基于这个runner的继承和重用都是可以的,这样能更加具有灵活性。它继承ParentRunner,Junit4要求,执行器的构造函数要把测试类传 进来。这个类的实现了ParentRunner的runChild(真正执行测试的方法,每个测试方法都会执行 runChild),describeChild(FrameworkMethod method)(用来获取测试类的元数据信息,以及方法和类的信息),一些验证的方法,这些验证方法在ParentRunner构造的时候就会开始验证。 另外一个比较重要的方法是:

 

methodBlock(FrameworkMethod method)

 

method里面包含当前要测试的方法。

 

这个方法的作用验证方法能否执行,然后把当前测试类的信息(当前类,测试的方法)传给InvokeMethod,以待后续测试方法的执行,接着获取当前类的元数据信息,保存起来。

 

2. ParentRunner:Junit4测试执行器的基类,它提供了一个测试器所需要的大部分功能。继承它的类需要实现:

 

protected abstract List<T> getChildren();

 

protected abstract Description describeChild(T child);

 

protected abstract void runChild(T child, RunNotifier notifier);

 

3. Statement:在运行期时,执行test case前可以插入一些用户动作,它就是描述这些动作的一个类。继承这个类要实现:

 

复制代码
    /**

     * Run the action, throwing a {@code Throwable} if anything goes wrong.

     */

     public abstract void evaluate() throws Throwable;
复制代码

 

 这个方法,这个方法会先后在ParentRunner.run()和ParentRunner.runLeaf()这两个方法里面调用。另外,我们可以自定义一个Statement,并且实现evaluate()方法。

 

4. TestRule:TestRule 可以描述一个或多个测试方法如何运行和报告信息的接口。在TestRule中可以额外加入一些check,我们可以让一个test case失败/成功,也可以加入一些setup和cleanup要做的事,也可以加入一些log之类的报告信息。总之,跑test case之前的任何事,都可以在里面做。需要实现apply()方法。

 

复制代码
    /**

     * Modifies the method-running {@link Statement} to implement this

     * test-running rule.

     * @param base The {@link Statement} to be modified * @param description A {@link Description} of the test implemented in {@code base} * @return a new statement, which may be the same as {@code base}, * a wrapper around {@code base}, or a completely new Statement. */ Statement apply(Statement base, Description description);
复制代码

 

 这两个类的用法可以见后面的综合例子。

 

5. Description:存储着当前单个或多个test case的描述信息。这些信息跟逻辑不关,比如元数据信息等。实例化Description用Description.createTestDescription()方法。

 

 

 

6. RunNotifier:运行时通知器。执行Runner.run(RunNotifier runNotifier)方法时,需要传一个RunNotifier进去,这个RunNotifier是事件的管理器,它能帮助我们监控测试执行的情况。

 

 

 

7. InvokeMethod:最终执行test case里面的测试方法通过这个类来做,这个类会间接调用Method.invoke()方法通知编译器执行@test方法。

 

Junit4启动test case到结束整个过程概述

 

  1. Junit4Builder编译器会构造Test运行器,如BlockJUnit4ClassRunner,BlockJUnit4ClassRunner 会通过自己的构造器,把当前测试类传到runner里。
  2. 运行ParentRunner.run()方 法,run 方法会获取测试类的Description信息,Description信息会包含测试类的信息,然后执行 classBlock(RunNotifier),这个方法获取Statement信息,首先构造一个childrenInvoker,然后在 Statement的evaluate()方法调用runChildren()方法,用来真正地执行test方法,这个步骤会等到测试真正执行后开始做。 现在是先获取Statement会处理三种注解,@Before,@After,@Rule,把标注这些注解的方法分别放在集合里,以便后面能够处理这些 方法。
  3. 准备工作都做好之后,会执行步骤2里从 classBlock(RunNotifier)获取到的Statement的evaluate()方法,这个方法用来对Statement来说是开了一 个口,用户可以自定义Statement的方法,不过在这里,evaluate()主要是来执行步骤2调用的runChildren()方法。
  4. runChildren()方法的作用是:遍 历测试类的所有测试方法(getFilteredChildren),开启线程调度fScheduler,调度线程给每一个测试方法,然后执行 Runnable.run()方法,让测试执行器,让测试执行器可以执行测试类的测试方法(runChild)。
  5. 执行测试方法首先会判断方法是否含有@Ignore注解,如果有,那么忽略它的测试。如果没有那么执行runLeaf()方法。这个方法是真正我们执行测试的开始。
  6. RunLeaf(Statement, Description, RunNotifier),首先Statement是有methodBlock(FrameworkMethod)产生,FrameworkMethod 存着当前要执行的测试方法,在这个方法里,用了反射机制。这时候Junit4会构造RunRules会把Statement, Description apply()到MethodRules, TestRule进去,也就是说,我们在外部构造的带有@Rule,@Before, @After等就在这里执行,如:
    @Rule
    public final TestRule testRule = new CommonRule();

     此时,我们就可以在我们新构建的CommonRule类里面,的apply()方法,做一些对test的预处理,比如预处理连接数据库字符串,读取方法上元数据的信息等;

  7. 然后就真正执行 RunLeaf(Statement, Description, RunNotifier),通过传进来的参数构建EachTestNotifier,执行fireTestStarted,然后,再打开对 话,statement.evaluate(),这个执行过程中,会到InvokeMethod类,然后调用 InvokeMethod.evaluate(),最后调用Method.invoke()方法真正地执行了test实体。测试开始了。

 

备注:就如刚所说的,真正开始测试前,我们可以用apply()进行一些处理,同样地,我们可以在apply()方法中,创建用户Statement,这样就能在evaluate()方法中,做一些操作。如执行脚本,日志等。

 

元数据的执行顺序

 

1. 获取元数据信息的顺序

 

@BeforeClass -> @AfterClass -> ClassRule -> @Test(拿元数据里的expect Exception) -> @Test(拿元数据里的timeout信息) -> @Before -> @After -> @Rule,

 

2. 注解所标注的方法执行顺序

 

@ClassRule(TestRule.apply()) -> @BeforeClass -> @Rule(TestRule.apply())  -> @Before -> @Test(test method1) ->@After -> if existed @Rule, then Statement.evaluate() -> @Rule(TestRule.apply()) -> @Before -> @Test(test method2) -> @After -> if existed @Rule, then Statement.evaluate() … -> @AfterClass -> if existed @ClassRule, then Statement.evaluate()

 

通过Statement.evaluate()执行他们的方法实体,最终执行测试方法的主体。

 

附录:

 

TestRule Statement以及注解标识的方法执行顺序代码示例

 

 

 

复制代码
  1 package com.citi.risk.services.credit.facility.impl;
  2 
  3 import java.io.Closeable;  4 import java.io.IOException;  5  6 import org.junit.After;  7 import org.junit.AfterClass;  8 import org.junit.Before;  9 import org.junit.BeforeClass;  10 import org.junit.ClassRule;  11 import org.junit.Rule;  12 import org.junit.Test;  13 import org.junit.rules.ExpectedException;  14 import org.junit.rules.TestRule;  15 import org.junit.runner.Description;  16 import org.junit.runners.model.Statement;  17  18 /**  19  * 执行顺序如下: 默认test方法的执行顺序是随机的,没有顺序  20  * @ClassRule(TestRule.apply()) -> @BeforeClass -> @Rule(TestRule.apply()) -> @Before  21  * -> @Test(test method1) ->@After -> if existed @Rule, then Statement.evaluate()  22  * -> @Rule(TestRule.apply()) -> @Before -> @Test(test method2) -> @After  23  * -> if existed @Rule, then Statement.evaluate() … -> @AfterClass  24  * -> if existed @ClassRule, then Statement.evaluate()  25  * @author 草原战狼  26  *  27 */  28 public class TestClass {  29  30  @Rule  31 public ExpectedException expectedException = ExpectedException.none();  32  33  @Rule  34 public TestRule testRule = new TestRuleValueImpl();  35  36  @Rule  37 public TestRule testRuleMethod() {  38  System.out.println();  39 System.out.println("@Rule Method");  40 return new TestRuleMethodImpl();  41  }  42  @ClassRule  43 public static TestRule testClassRuleMethod() {  44 System.out.println("@ClassRule Method");  45 return new TestRuleMethodImpl();  46  }  47  48 static class TestRuleValueImpl implements TestRule{  49  @Override  50 public Statement apply(Statement base, Description description) {  51 System.out.println("@Rule property--TestRuleValueImpl execute apply()");  52 return new StatementValueImpl(base);  53  }  54  }  55  56 static class StatementValueImpl extends Statement {  57  Statement base;  58  StatementValueImpl(Statement base) {  59 this.base = base;  60  }  61  @Override  62 public void evaluate() throws Throwable {  63 System.out.println("@Rule property--StatementValueImpl execute evaluate()");  64  base.evaluate();  65  }  66  67  }  68 static class TestRuleMethodImpl implements TestRule{  69  @Override  70 public Statement apply(Statement base, Description description) {  71 System.out.println("@Rule method--TestRuleMethodImpl execute apply()");  72 return new StatementMethodImpl(base);  73  }  74  75  }  76  77 static class StatementMethodImpl extends Statement {  78  Statement base;  79  StatementMethodImpl(Statement base) { 80 this.base = base; 81 } 82 @Override 83 public void evaluate() throws Throwable { 84 System.out.println("@Rule Method--StatementMethodImpl execute evaluate()"); 85 base.evaluate(); 86 } 87 88 } 89 static class ExpensiveManagedResource implements Closeable { 90 @Override 91 public void close() throws IOException { 92 } 93 } 94 95 static class ManagedResource implements Closeable { 96 @Override 97 public void close() throws IOException { 98 } 99 } 100 101 @BeforeClass 102 public static void setUpClass() { 103 System.out.println("@BeforeClass setUpClass"); 104 myExpensiveManagedResource = new ExpensiveManagedResource(); 105 } 106 107 @AfterClass 108 public static void tearDownClass() throws IOException { 109 System.out.println("@AfterClass tearDownClass"); 110 myExpensiveManagedResource.close(); 111 myExpensiveManagedResource = null; 112 } 113 114 private ManagedResource myManagedResource; 115 private static ExpensiveManagedResource myExpensiveManagedResource; 116 117 private void println(String string) { 118 System.out.println(string); 119 } 120 121 @Before 122 public void setUp() { 123 this.println("@Before setUp"); 124 this.myManagedResource = new ManagedResource(); 125 } 126 127 @After 128 public void tearDown() throws IOException { 129 this.println("@After tearDown"); 130 this.myManagedResource.close(); 131 this.myManagedResource = null; 132 this.println(" "); 133 } 134 135 @Test 136 public void test1() { 137 this.println(" @Test test1() begin"); 138 this.println(" @Test test1() execute during evaluate()"); 139 this.println(" @Test test1() finished"); 140 } 141 142 @Test 143 public void test2() { 144 this.println(" @Test test2() begin"); 145 this.println(" @Test test2() execute during evaluate()"); 146 this.println(" @Test test2() finished"); 147 } 148 149 @Test 150 public void test3() { 151 this.println(" @Test test3() begin"); 152 String hi = " @Test test3() execute during evaluate()"; 153 expectedException.expect(Exception.class); 154 expectedException.expectMessage("ddd"); 155 this.println(hi); 156 this.println(" @Test test3() finished."); 157 } 158 }
复制代码

 

  执行的结果如下:

 

 

 

复制代码
 1 @ClassRule Method
 2 @Rule method--TestRuleMethodImpl execute apply()
 3 @Rule Method--StatementMethodImpl execute evaluate()  4 @BeforeClass setUpClass // 预备期结束  5 // 第一个测试方法开始到结束  6 @Rule Method 7 @Rule method--TestRuleMethodImpl execute apply() 8 @Rule property--TestRuleValueImpl execute apply() 9 @Rule property--StatementValueImpl execute evaluate() 10 @Rule Method--StatementMethodImpl execute evaluate() 11 @Before setUp 12 @Test test1() begin 13 @Test test1() execute during evaluate() 14 @Test test1() finished 15 @After tearDown 16 17 // 第二个方法开始到结束,我们可以在apply() 和 evaluate()这两个方法做一些操作。 18 @Rule Method 19 @Rule method--TestRuleMethodImpl execute apply() 20 @Rule property--TestRuleValueImpl execute apply() 21 @Rule property--StatementValueImpl execute evaluate() 22 @Rule Method--StatementMethodImpl execute evaluate() 23 @Before setUp 24  @Test test2() begin 25  @Test test2() execute during evaluate() 26  @Test test2() finished 27 @After tearDown 28 29 // 第三个方法,这三个方法执行的顺序是随机的,当然Junit4提供了某些排序方式可以处理 30 @Rule Method 31 @Rule method--TestRuleMethodImpl execute apply() 32 @Rule property--TestRuleValueImpl execute apply() 33 @Rule property--StatementValueImpl execute evaluate() 34 @Rule Method--StatementMethodImpl execute evaluate() 35 @Before setUp 36 @Test test3() begin 37 @Test test3() execute during evaluate() 38 @Test test3() finished. 39 @After tearDown 40 41 @AfterClass tearDownClass
复制代码

 

转载于:https://www.cnblogs.com/zhouzf007/p/4915855.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值