知道 PHP 有一个 phpUnit 做单元测试,所以在写 java 的时候也顺便了解一下 JUnit 如何代码做单元测试
概述
在 IDEA 和 Maven 的下面,如何使用 JUnit 去编写测试单元。这里我使用的 JUnit 版本是 3.8.1,JUnit4.0 以上的版本在具体用法上会有些许差异。
栗子
项目源代码: jsp-basic
maven 配置:
一般而言,使用 maven 构建的项目都会自带 junit,并且/src/test 目录就是专门供写测试单元的目录。
idea 配置:
我使用的是 Mac 版本的 idea,首先是安装 JUnit 的 plugin,在 preference->plugin->Browse repositories-> 输入 JUnit,安装 JUnit Generator V2.0。
它具体的样子应该长这样:
安装成功后,我们执行 JUnit 的 test 案例时,应该会出现以下结果:
可以看见,左边的是对应我测试哪个类,然后该类下测试的方法是什么等等,右边的输出表示了测试结果和输出信息。
junit3.8 下的测试代码
Calculate 类:
package com.liumapp.jspbasic.util; /** * Created by liumapp on 6/26/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class Calculate { public int add (int a , int b ) { return a + b; } public int subtract (int a , int b ) { return a - b; } public int multiply (int a , int b) { return a * b; } public int divide (int a , int b) { return a / b; } }
CalculateTest 类:
package com.liumapp.jspbasic.util; import junit.framework.TestCase; /** * Created by liumapp on 6/26/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class CalculateTest extends TestCase { /** * Create the test case * * @param testName name of the test case */ public CalculateTest( String testName ) { super( testName ); } /** * Rigourous Test :-) */ public void testAdd() { System.out.println("test add begin"); assertEquals(6 , new Calculate().add(3 ,3)); } public void testSubtract () { System.out.println("test subtract begin"); assertEquals(1 , new Calculate().subtract(2 , 1)); } public void testDivide () { System.out.println("test divide begin"); assertEquals(1 , new Calculate().divide(1 ,1)); } public void testMultiply () { System.out.println("test multiply begin"); assertEquals(1 , new Calculate().multiply(1,1)); } }
CalculateTest 类的运行结果即为上面的截图所示。
根据上面的栗子可以很简单的看出来,JUnit 最基本的测试类编写规则:
- 类要继承 junit.framework.TestCase
- 测试方法命名的规则为:test+ 要测试的类的方法名
- 利用 asset 断言去判断结果的正确与否,至于代码逻辑的正确与否,junit 似乎爱莫能助。
上面的栗子是没有错误发生的,如果我们将 testAdd()方法里面的 assetEquals(6 , new Calculate().add(3,3));改为 assetEquals(5, new Calculate().add(3 ,3));那么测试将会报错,因为 3+3=6 这与预期的 5 不符合。
JUnit Generator V2.0 的使用
这一款插件跟 idea 自带的 JUnit 不同,区别在于它是用来自动生成测试单元的,具体用法:
比如我们上面提到的 Calculate 类,如果要自动生成它的测试单元,那步骤是这样的:
- 进入这个类的视图
- 按 Ctrl+ 回车,在开打的下拉框中选择 JUnit3
- 代码自动生成成功,但是这款插件在设计的时候似乎并没有考虑用户有使用 maven 的情况,所以它生成的测试单元我们还需要稍作改动,使之跟我们的项目目录结构相对应。
自动生成的测试单元目录结构如图所示:
/src/main/java/test/下为自动生成的测试单元,而我们实际上应该使用的测试单元在/src/test/java/目录下,所以改动的时候只需要移动一下即可。或者有某位大神知道怎么改动这个插件让它变聪明点,请在评论区指导一下。
JUnit3 和 JUnit4 的区别
这里列出来的区别并不完善,我发现了新的区别会在以后进行更新。
- JUnit3 需要继承 junit.framework.TestCase,JUnit4 不需要继承任何父类
- JUnit4 新引入了注解机制,JUnit3 没有。
- JUnit4 对比 JUnit3 新增了 setupbeforeclass 和 teardownafterclass 这两个方法
JUnit 运行流程
假设有下面一个测试类:
package com.liumapp.jspbasic; import com.liumapp.jspbasic.util.Calculate; import junit.framework.TestCase; /** * Created by liumapp on 6/26/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class JunitFlowTest extends TestCase { @Override protected void setUp() throws Exception { System.out.println("this is setUp"); } @Override protected void tearDown() throws Exception { System.out.println("this is tearDown"); } /** * Rigourous Test :-) */ public void testAdd() { System.out.println("test add begin"); assertEquals(6 , new Calculate().add(3 ,3)); } public void testSubtract () { System.out.println("test subtract begin"); assertEquals(1 , new Calculate().subtract(2 , 1)); } }
它在运行的时候,打印的结果为:
this is setUp test add begin this is tearDown this is setUp test subtract begin this is tearDown
由此可见,JUnit 在每一个测试方法执行之前,会去执行一遍 setUp 方法,之后完成之后,会去执行一遍 tearDown 方法,在 JUnit4 里面,新增了 setUpBeforeClass 和 tearDownAfterClass 两个方法,第一个表示 JUnit 测试类开始测试的时候执行一遍,第二个表示 JUnit 类测试结束的时候执行。(有点类似构造函数和析构函数)
setUpBeforeClass
它会在所有方法被调用前执行,而且该方法是静态的,所以当测试类被加载后接着就会运行它,而且在内存中它只会存在一份实例,比较适合用来加载配置文件。
tearDownAfterClass
通常用来清理资源,比如关闭数据库的连接等。
JUnit4 的常用注解
- @Test:将一个普通的方法修饰成为一个测试方法
- @Test(expected=ArithmeticException.class): 抛出异常
- @Test(timeout=毫秒):最大操作时间
- @BeforeClass:它会在所有的方法运行前被执行,static 修饰,相当于 setUpBeforeClass
- @AfterClass:它会在所有的方法运行结束后被执行,static 修饰,相当于 tearDownAfterClass
- @Before:会在每一个测试方法被运行前执行一次
- @After:会在每一个测试方法运行后被执行一次
- @Ignore:所修饰的测试方法将会被忽略,不会被执行
- @RunWith:可以更改测试运行器 , 比如:org.junit.runner.Runner
批量测试
在/src/test 下创建一个 TestAll 类,其代码如下:
package com.liumapp.jspbasic; import com.liumapp.jspbasic.util.CalculateTest; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Created by liumapp on 6/26/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class TestAll extends TestCase{ public static Test suite() { TestSuite ts = new TestSuite(); ts.addTestSuite(CalculateTest.class); ts.addTestSuite(JunitFlowTest.class); return ts; } }
对于 JUnit3.8 而言,我们要利用 TestSuite 的 addTestSuite 来进行批量测试,上面的代码就是把 CalculateTest 和 JunitFlowTest 这两个测试包含进去,所以我们在运行 TestAll 这个测试类的时候,CalculateTest 和 JunitFlowTest 这两个测试将会被执行。
而对于 JUnit4 而言,则是通过注解机制来实现:
@RunWith(Suite.class) @Suite.SuiteClass({CalculateTest.class,JunitFlowTest.class}) public class TestAll { //内容为空 }
参数化测试
参数化测试目前来看,在 JUnit4 下支持比较良好,JUnit3.8 下我暂时没有找到一个合适的解决方案。
package com.liumapp.jspbasic; import com.liumapp.jspbasic.util.Calculate; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.Arrays; import java.util.Collection; import junit.framework.TestCase; /** * Created by liumapp on 6/26/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ @RunWith(Parameterized.class) public class ParameterTest { int expected = 0; int input1 = 0; int input2 = 0; public ParameterTest( int expected , int input1 , int input2) { this.expected = expected; this.input1 = input1; this.input2 = input2; } @Parameterized.Parameters public static Collection<Object[]> t() { return Arrays.asList(new Object[][]{ {3,1,2}, {4,2,2} }); } @Test public void testAdd() { System.out.println("test add begin: while expected is " + expected); TestCase.assertEquals(expected , new Calculate().add(input1 ,input2)); } }
上面的测试代码在执行后,将会以 3,1,2 和 4,2,2 这两组数据去测试 Calculate().add()方法。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于