知道 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()方法。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于