Hello , JUnit -- IDEA and Maven

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

知道 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 引用 • 3455 回帖 • 167 关注
  • IDEA

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

    181 引用 • 400 回帖
  • Maven

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

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

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

    3194 引用 • 8214 回帖 • 1 关注

相关帖子

欢迎来到这里!

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

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