【原创】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 }
直接点击右键,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 和 执行顺序。且听下回分解。
草原战狼淘宝小店:http://xarxf.taobao.com/ 淘宝搜小矮人鞋坊,主营精致美丽时尚女鞋,为您的白雪公主挑一双哦。谢谢各位博友的支持。
===============================================================================
========================== 以上分析仅代表个人观点,欢迎指正与交流 ==========================
========================== 草原战狼博客,转载请注明出处,万分感谢 ==========================
===============================================================================