Hello , JUnit -- IDEA and Maven

本贴最后更新于 2706 天前,其中的信息可能已经沧海桑田

知道 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。
它具体的样子应该长这样:
plugin.jpg

安装成功后,我们执行 JUnit 的 test 案例时,应该会出现以下结果:

test.jpg

可以看见,左边的是对应我测试哪个类,然后该类下测试的方法是什么等等,右边的输出表示了测试结果和输出信息。

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 的情况,所以它生成的测试单元我们还需要稍作改动,使之跟我们的项目目录结构相对应。

自动生成的测试单元目录结构如图所示:

testResult.jpg

/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()方法。

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3453 回帖 • 203 关注
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    180 引用 • 400 回帖
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 303 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...