不多说,直接练习学习。
1、将Junit4单元测试包引入项目:项目右键——“属性”,选择“Java Build Path”,然后到右上选择“Libraries”标签,之后在最右边点击“Add Library…”按钮,选择JUnit4并点击确定。
2.新建一个项目叫JUnit_Test,我们编写一个Calculator待测试类
1 public class Calculator { 2 3 public int add(int a, int b) { 4 return a + b; 5 } 6 7 public int substract(int a, int b) { 8 return a - b; // Bug:result=result-n 9 } 10 11 public int multiply(int a, int b) { 12 return a * b; 13 } 14 15 public int divide(int a, int b) throws Exception { 16 if(0 == b){ 17 throw new Exception("除数不能为0"); 18 } 19 return a / b; 20 } 21 22 public int square(int n) { 23 return n * n; 24 } 25 26 public void squareRoot(int n) { 27 for (;;) 28 ; 29 } 30 }
3.编写单元测试类
New>"Junit Test Case",选择New Junit 4 test ,勾选which method stubs would you like to create?
选择Class under test,点击Next,选择方法,Finish。
1 package com.test; 2 3 import static org.junit.Assert.*; 4 5 import org.junit.After; 6 import org.junit.AfterClass; 7 import org.junit.Before; 8 import org.junit.BeforeClass; 9 import org.junit.Ignore; 10 import org.junit.Test; 11 12 public class Test1 { 13 14 private Calculator calculator = new Calculator(); 15 16 @BeforeClass// 注意,这里必须是static...因为方法将在类被装载的时候就被调用(那时候还没创建实例) 17 public static void setUpBeforeClass() throws Exception { 18 System.out.println("global"); 19 } 20 21 @AfterClass 22 public static void tearDownAfterClass() throws Exception { 23 System.out.println("global destory"); 24 } 25 26 @Before 27 public void setUp() throws Exception { 28 System.out.println("一个测试开始.."); 29 } 30 31 @After 32 public void tearDown() throws Exception { 33 System.out.println("一个测试结束.."); 34 } 35 36 @Ignore 37 @Test 38 public void testAdd() { 39 int result = calculator2.add(1, 2); 40 assertEquals(3,result); 41 } 42 43 @Test 44 public void testSubstract() { 45 int result = calculator2.substract(5, 2); 46 assertEquals(3, result); 47 48 } 49 50 @Test 51 public void testMultiply() { 52 int result = calculator2.multiply(4, 2); 53 assertEquals(8, result); 54 } 55 56 @Test(expected = Exception.class) 57 public void testDivide() throws Exception { 58 System.out.println("teddd"); 59 calculator2.divide(4, 0);// 很简单的办法....... 60 } 61 62 @Test(timeout = 1000)// 单位为毫秒 63 public void testSquareRoot() { 64 calculator2.squareRoot(4); 65 } 66 67 }
Run As->JUnit Test,显示如图
可以看到,CalculatorTest类中总共有5个测试用例,ignore了一个,3个测试用例通过,testSquareRoot测试不通过(因为超时),所以整个的测试结果飘红了。同时,控制台的输出结果为:
global 一个测试开始.. 一个测试结束.. 一个测试开始.. teddd 一个测试结束.. 一个测试开始.. 一个测试结束.. 一个测试开始.. 一个测试结束.. global destory
注解说明:
@Test:
表明该方法是一个测试方法
@BeforeClass 和 @AfterClass:
测试用例初始化时执行 @BeforeClass方法,当所有测试执行完毕之后,执行@AfterClass进行收尾工作。标注、@BeforeClass 和 @AfterClass的方法必须是static的,因为方法将在类被装载的时候就被调用,那时候还没创建测试对象实例。
@Before:
使用了该元数据的方法在每个测试方法执行之前都要执行一次。
@After:
使用了该元数据的方法在每个测试方法执行之后要执行一次。
@Test(expected=*.class) :
通过@Test元数据中的expected属性验证是否抛出期望的异常,expected属性的值是一个异常的类型,如果抛出了期望的异常,则测试通过,否则不通过。
@Test(timeout=xxx):
该元数据传入了一个时间(毫秒)给测试方法,如果测试方法在制定的时间之内没有运行完,则测试也失败。
@Ignore:
该元数据标记的测试方法在测试中会被忽略。同时可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:@lgnore("该方法还没有实现"),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。
在test方法内除了使用Assert的assertEquals()方法外,还能使用assertFalse()、assertTrue()、assertNull()、assertNotNull()、assertSame()、assertNotSame()等断言函数。而且如果使用的是Junit4,结合Hamcrest,使用
assertThat([value], [matcher statement])方法可以实现更灵活的断言判断(前提是引入hamcrest的jar包)。
例如:
// is匹配符表明如果前面待测的object等于后面给出的object,则测试通过
assertThat( testedObj, is( object) );
// containsString匹配符表明如果测试的字符串包含指定的子字符串则测试通过
assertThat( testedString, containsString( "developerWorks" ) );
// greaterThan匹配符表明如果所测试的数值testedNumber大于16.0则测试通过
assertThat( testedNumber, greaterThan(16.0) );
// closeTo匹配符表明如果所测试的浮点型数testedDouble在20.0±0.5范围之内则测试通过
assertThat( testedDouble, closeTo( 20.0, 0.5 ) );
//hasItem匹配符表明被测的迭代对象含有元素element项则测试通过assertThat(iterableObject, hasItem (element));
4、参数化测试
上面的Caculator待测试类里,现在我如果想给square方法多弄几个测试用例,按照上面的方法,我应该写好几个@Test方法来测试,或者每次测完再改一下输入的值和期望得到的值,好麻烦。JUnit提供如下的测试:
1 package com.test; 2 3 import static org.junit.Assert.assertEquals; 4 5 import java.util.Arrays; 6 import java.util.Collection; 7 import org.junit.Test; 8 import org.junit.runner.RunWith; 9 import org.junit.runners.Parameterized; 10 import org.junit.runners.Parameterized.Parameters; 11 12 @RunWith(Parameterized.class) 13 public class Test2 { 14 15 private Calculator2 calculator2 = new Calculator2(); 16 private int param; 17 private int result; 18 19 public Test2(int param, int result) { 20 this.param = param; 21 this.result = result; 22 } 23 24 @Parameters 25 public static Collection data(){ 26 return Arrays.asList(new Object[][]{ 27 {2,4}, 28 {0,0}, 29 {-3,9} 30 }); 31 } 32 33 @Test 34 public void squareTest(){ 35 int temp = calculator2.square(param); 36 assertEquals(result, temp); 37 } 38 }
运行结果显示:
测试通过了,Test2类里的parameter是每次的测试输入,result就是测试的结果。所有的测试输入和期望结果都在@Parameters标注的data函数的返回的Collection集合里,2的期望得到的平方结果值是4,0期望得到0,-3期望得到9。
下面我们对上述代码进行分析。首先,你要为这 种测试专门生成一个新的类,而不能与其他测试共用同一个类,此例中我们定义了一个Test2类。然后,你要为这个类指定一个Runner,而不 能使用默认的Runner了,因为特殊的功能要用特殊的Runner嘛。@RunWith(Parameterized.class)这条语句就是为这个 类指定了一个ParameterizedRunner。第二步,定义一个待测试的类,并且定义两个变量,一个用于存放参数,一个用于存放期待的结果。接下 来,定义测试数据的集合,也就是上述的data()方法,该方法可以任意命名,但是必须使用@Parameters标注进行修饰。这个方法的框架就不予解 释了,大家只需要注意其中的数据,是一个二维数组,数据两两一组,每组中的这两个数据,一个是参数,一个是你预期的结果。比如我们的第一组{2, 4},2就是参数,4就是预期的结果。这两个数据的顺序无所谓,谁前谁后都可以。之后是构造函数,其功能就是对先前定义的两个参数进行初始化。在这里你可 要注意一下参数的顺序了,要和上面的数据集合的顺序保持一致。如果前面的顺序是{参数,期待的结果},那么你构造函数的顺序也要是“构造函数(参数,期待的结果)”,反之亦然。最后就是写一个简单的测试例了,和前面介绍过的写法完全一样,在此就不多说。
五、Runner(运行器)
把测试代码提交给JUnit框架后,框架如何来运行代码呢?答案就是——Runner。在JUnit中有很多个 Runner,他们负责调用测试代码,每一个Runner都有各自的特殊功能,要根据需要选择不同的Runner来运行测试代码。JUnit中有一个默认Runner,如果没有指定,那么系统自动使用默认 Runner来运行你的代码。这里参数化测试就没有再用默认的Runner了。
1 import org.junit.internal.runners.TestClassRunner; 2 import org.junit.runner.RunWith; 3 //使用了系统默认的TestClassRunner,与下面代码完全一样 4 public class CalculatorTest …{…} 5 @RunWith(TestClassRunner.class) 6 public class CalculatorTest …{…}
六、打包测试
1 package com.test; 2 3 import org.junit.runner.RunWith; 4 import org.junit.runners.Suite; 5 6 /** 7 * 大家可以看到,这个功能也需要使用一个特殊的Runner, 8 * 因此我们需要向@RunWith标注传递一个参数Suite.class。 9 * 同时,我们还需要另外一个标注@Suite.SuiteClasses, 10 * 来表明这个类是一个打包测试类。我们把需要打包的类作为参数传递给该标注就可以了。 11 * 有了这两个标注之后,就已经完整的表达了所有的含义,因此下面的类已经无关紧要, 12 * 随便起一个类名,内容全部为空既可 13 * 14 */ 15 @RunWith(Suite.class) 16 @Suite.SuiteClasses({Test1.class,Test2.class}) 17 public class AllTest { 18 19 }
这个测试类包含了上面的Test1.class和Test2.class里面所有的测试函数,它的目的就是进行打包所有的测试。
参考:
http://tonl.iteye.com/blog/1948869
http://tips1000.com/archives/189.html