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

    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 }
View @Test Code

直接点击右键,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 }
View Assert Code

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

回答: 可以。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 }
View Suite Code

 

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 }
View CaculatorClassForTest Code

 

 

 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 }
View TestCaculatorClass Code

 

 以上两个类就是测试了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 }
View Categories Code
 

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     }
View Address Code

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     }
View AddressTest Code

问题三:不想执行某个类的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 和 执行顺序。且听下回分解。

 

草原战狼淘宝小店:http://xarxf.taobao.com/ 淘宝搜小矮人鞋坊,主营精致美丽时尚女鞋,为您的白雪公主挑一双哦。谢谢各位博友的支持。

===============================================================================

==========================    以上分析仅代表个人观点,欢迎指正与交流   ==========================

==========================    草原战狼博客,转载请注明出处,万分感谢   ==========================

===============================================================================

 

posted @ 2014-01-22 20:40  草原战狼  阅读(21355)  评论(0编辑  收藏  举报
草原战狼淘宝小店

No one indebted for others,while many people don't know how to cherish others.

No one indebted for others,while many people don't know how to cherish others.

Don‘t cry because it is over, smile because it happened.

Don‘t try so hard, the best things come when you least expect them to.