本文共 10844 字,大约阅读时间需要 36 分钟。
public class AddOperation { public int add(int x, int y) { return x + y; }}
我们要测试add这个方法,我们写单元测试得这么写:
import junit.framework.TestCase;import static org.junit.Assert.*;public class AddOperationTest extends TestCase { public void setUp() throws Exception { } public void tearDown() throws Exception { } public void testAdd() { System.out.println("add"); int x = 0; int y = 0; AddOperation instance = new AddOperation(); int expResult = 0; int result = instance.add(x, y); assertEquals(expResult, result); }}
可以看到上面的类使用了JDK5中的静态导入,这个相对来说就很简单,只要在import关键字后面加上static关键字,就可以把后面的类的static的变量和方法导入到这个类中,调用的时候和调用自己的方法没有任何区别。
我们可以看到上面那个单元测试有一些比较霸道的地方,表现在:
1.单元测试类必须继承自TestCase。
2.要测试的方法必须以test开头。 如果上面那个单元测试在JUnit 4中写就不会这么复杂。代码如下:
import junit.framework.TestCase;import org.junit.After;import org.junit.Before;import org.junit.Test;import static org.junit.Assert.*;/** * @ClassName: AddOperationTest * @Description: * @author chenjazz@foxmail.com * @date 2015年5月11日 下午1:29:53 */public class AddOperationTest extends TestCase { public AddOperationTest() { } @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void add() { System.out.println("add"); int x = 0; int y = 0; AddOperation instance = new AddOperation(); int expResult = 0; int result = instance.add(x, y); assertEquals(expResult, result); }}
我们可以看到,采用Annotation的JUnit已经不会霸道的要求你必须继承自TestCase了,而且测试方法也不必以test开头了,只要以@Test元数据来描述即可。 从上面的例子可以看到在JUnit 4中还引入了一些其他的元数据,下面一一介绍:
@Before:
使用了该注解的方法在每个测试方法执行之前都要执行一次。 @After: 使用了该注解的方法在每个测试方法执行之后要执行一次。 注意:@Before和@After标示的方法只能各有一个。这个相当于取代了JUnit以前版本中的setUp和tearDown方法,当然你还可以继续叫这个名字,不过JUnit不会霸道的要求你这么做了。 @Test(expected=*.class) 在JUnit4.0之前,对错误的测试,我们只能通过fail来产生一个错误,并在try块里面assertTrue(true)来测试。现在,通过@Test元数据中的expected属性。expected属性的值是一个异常的类型 @Test(timeout=xxx): 该元数据传入了一个时间(毫秒)给测试方法, 如果测试方法在制定的时间之内没有运行完,则测试也失败。 @ignore: 该元数据标记的测试方法在测试中会被忽略。当测试的方法还没有实现,或者测试的方法已经过时,或者在某种条件下才能测试该方法(比如需要一个数据库联接,而在本地测试的时候,数据库并没有连接),那么使用该标签来标示这个方法。同时,你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:@lgnore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。
package com.jtest;import static org.junit.Assert.*;import org.junit.After;import org.junit.Before;import org.junit.Ignore;import org.junit.Test;public class CalculatorTest { private static Calculator c=new Calculator(); @Before public void setUp() throws Exception { c.clear(); } @After public void tearDown() throws Exception { } @Test public void testAdd() { c.add(3); c.add(5); assertEquals(8,c.getResult()); } @Test public void testSubstract() { c.add(5); c.substract(2); assertEquals(3,c.getResult()); } @Ignore("方法未实现!") @Test public void testMultiply() { } @Test public void testDivide() { c.add(10);//**** c.divide(2); assertEquals(5,c.getResult()); }}右键测试程序,选择run as...
@Test public void testAdd() ...{ calculator.add(2); calculator.add(3); assertEquals(5, calculator.getResult()); }我们想测试一下“加法”功能时候正确,就在测试方法中调用几次add函数,初始值为0,先加2,再加3,我们期待的结果应该是5。如果最终实际结果也是5,则说明add方法是正确的,反之说明它是错的。assertEquals(5, calculator.getResult());就是来判断期待结果和实际结果是否相等,第一个参数填写期待结果,第二个参数填写实际结果,也就是通过计算得到的结果。这样写好之后,JUnit会自动进行测试并把测试结果反馈给用户。
public void squareRoot(int n) { for (; ;) ; //死循环 }
@Test(expected = ArithmeticException.class) public void divideByZero() { calculator.divide(0); }
import org.junit.internal.runners.TestClassRunner; import org.junit.runner.RunWith; //使用了系统默认的TestClassRunner,与下面代码完全一样 public class CalculatorTest ...{...} @RunWith(TestClassRunner.class) public class CalculatorTest {...}
import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class AdvancedTest ...{ private static Calculator calculator = new Calculator(); @Before public void clearCalculator() ...{ calculator.clear(); } @Test public void square1() ...{ calculator.square(2); assertEquals(4, calculator.getResult()); } @Test public void square2() ...{ calculator.square(0); assertEquals(0, calculator.getResult()); } @Test public void square3() ...{ calculator.square(-3); assertEquals(9, calculator.getResult()); } }
import static org.junit.Assert.assertEquals; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; @RunWith(Parameterized.class) public class SquareTest { private static Calculator calculator = new Calculator(); private int param; private int result; @Parameters public static Collection data() ...{ return Arrays.asList(new Object[][]...{ ...{2, 4}, ...{0, 0}, ...{-3, 9}, }); } //构造函数,对变量进行初始化 public SquareTest(int param, int result) ...{ this.param = param; this.result = result; } @Test public void square() ...{ calculator.square(param); assertEquals(result, calculator.getResult()); } }
import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses(...{ CalculatorTest.class, SquareTest.class }) public class AllCalculatorTests ...{}大家可以看到,这个功能也需要使用一个特殊的Runner,因此我们需要向@RunWith标注传递一个参数Suite.class。同时,我们还需要另外一个标注@Suite.SuiteClasses,来表明这个类是一个打包测试类。我们把需要打包的类作为参数传递给该标注就可以了。有了这两个标注之后,就已经完整的表达了所有的含义,因此下面的类已经无关紧要,随便起一个类名,内容全部为空既可。