第一步:eclipse中新建一个项目,java build path中导入junit jar包(本文例子junit-4.9b1.jar)
第二步:新建一个package,导入如下四个文件
第三步:右键AllCalculatorTests(或者CalculatorTest、SquareTest),run as junit test,查看执行结果。
代码中的注释能够帮你理解Junit4。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package andycpp; public class Calculator { private static int result; // 静态变量,用于存储运行结果 public void add(int n) { result = result + n; } public void substract(int n) { result = result - 1; //Bug: 正确的应该是 result =result-n } public void multiply(int n){ } // 此方法尚未写好 public void divide(int n) { result = result / n; } public void square(int n) { result = n * n; } public void squareRoot(int n) { for (; ;) ; //Bug : 死循环 } public void clear() { // 将结果清零 result = 0; } public int getResult() { return result; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
package andycpp; /* * import static,这是一个静态包含(static),是JDK5中新增添的一个功能。也就是说,assertEquals是Assert类中的一系列的静态方法, * 一般的使用方式是Assert. assertEquals(),但是使用了静态包含后,前面的类名就可以省略了,使用起来更加的方便 * */ import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; //测试类名称任意 public class CalculatorTest { //你要测试哪个类,那么你首先就要创建一个该类的对象 private static Calculator calculator = new Calculator(); /* * @Before和@After是每个测试方法执行前后均需要执行, * 因此不适合累中耗资源,或者耗时过大的操作。 * @BeforeClass 和 @AfterClass两个Fixture来帮规避此问题。 * 从名字上就可以看出,用这两个Fixture标注的函数,只在测试用例 * 初始化时执行 @BeforeClass方法,当所有测试执行完毕之后,执行 * @AfterClass进行收尾工作。在这里要注意一下,每个测试类只能有 * 一个方法被标注为 @BeforeClass 或 @AfterClass, * 并且该方法必须是Public和Static的 * */ @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } /* * 我们非常希望每一个测试都是独立的,相互之间没有任何耦合度。 * 因此,我们就很有必要在执行每一个测试之前,对Calculator对象进行一个“复原”操作, * 以消除其他测试造成的影响。因此,“在任何一个测试执行之前必须执行的代码”就是一个Fixture, * 我们用@Before来标注它 这里不在需要@Test标注* * */ @Before public void setUp() throws Exception { calculator.clear(); } @After public void tearDown() throws Exception { } //@Test 标准的方法,返回值必须是void,而且无参数 @Test public void testAdd() { calculator.add(2); calculator.add(3); assertEquals(5,calculator.getResult());//第一个参数填写期待结果,第二个参数填写实际结果 } @Test public void testSubstract() { calculator.add(10); calculator.substract(2); assertEquals(8,calculator.getResult()); } /* * 如果你已经把该方法的测试用例写完,但该方法尚未完成,那么测试的时候一定是“失败”。 * 这种失败和真正的失败是有区别的,因此JUnit提供了一种方法来区别他们,那就是在这种 * 测试函数的前面加上@Ignore标注,这个标注的含义就是“某些方法尚未完成,暂不参与此次测试”。 * 这样的话测试结果就会提示你有几个测试被忽略,而不是失败。一旦你完成了相应函数,只需要把@Ignore标注删去, * 就可以进行正常的测试。 * */ @Ignore @Test public void testMultiply() { calculator.add(2); calculator.multiply(3); assertEquals(6,calculator.getResult()); } @Test public void testDivide() { calculator.add(8); calculator.divide(2); assertEquals(4, calculator.getResult()); } /* * 对于那些逻辑很复杂,循环嵌套比较深的程序, * 很有可能出现死循环,因此一定要采取一些预防措 施。 * 限时测试是一个很好的解决方案。我们给这些测试函数设定 * 一个执行时间,超过了这个时间,他们就会被系统强行终止, * 并且系统还会向你汇报该函数结束的原 因是因为超时,这样你就可以发现这些Bug了 * 测试例子calculator中的squareRoot是个死循环。 * */ @Test(timeout = 1000)//单位为毫秒 public void squareRoot() { calculator.squareRoot(4); assertEquals(2, calculator.getResult()); } /*使用@Test标注的expected属性,将我们要检验的异常传递给他, * 这样JUnit框架就能自动帮我们检测是否抛出了我们指定的异常 * */ @Test(expected = ArithmeticException.class) public void divideByZero() { calculator.divide(0); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
package andycpp; import java.util.Arrays; import java.util.Collection; import static org.junit.Assert.*; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; /* * 对于参数测试需要重新写一个类, 而不能与其他测试共用同一个类,此例中我们定义了一个SquareTest类。 * 然后,你要为这个类指定一个 Runner,而不能使用默认的Runner了,因为特殊的功能要用特殊的Runner嘛。 * @RunWith(Parameterized.class) * * */ @RunWith(Parameterized.class) public class SquareTest { private static Calculator calculator = new Calculator(); private int param; private int result; /* * 定义测试数据的集合,也就是上述的data()方法, * 该方法可以任意命名,但是必须使用@Parameters标注进行修饰。 * 这个方法的框架就不予解释了,大家只需要注意其中的数据,是一个二维数组, * 数据两两一组,每组中的这两个数据,一个是参数,一个是你预期的结果 * */ @Parameters public static Collection date(){ 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()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package andycpp; import org.junit.runner.RunWith; import org.junit.runners.Suite; /* * 大家可以看到,这个功能也需要使用一个特殊的Runner, * 因此我们需要向@RunWith标注传递一个参数Suite.class。 * 同时,我们还需要另外一个标注@Suite.SuiteClasses, * 来表明这个类是一个打包测试类。我们把需要打包的类作为参数传递给该标注就可以了。 * 有了这两个标注之后,就已经完整的表达了所有的含义,因此下面的类已经无关紧要, * 随便起一个类名,内容全部为空既可 * */ @RunWith(Suite.class) @Suite.SuiteClasses({ CalculatorTest.class, SquareTest.class }) public class AllCalculatorTests { } |