JUnit4单元测试基础篇
引言
JUnit作为Java语言的测试框架,在测试驱动开发(TDD)下扮演重要的角色。众所周知,无论开发大型项目还是一般的小型项目,
单元测试都至关重要。单元测试为软件可发测试维护提供了很大的便利。JUnit 4 作为最新版本,增添了许多新的特性,
结合Hamcrest,可以写出很多灵活的测试。从JUnit 4 开始 jar包放在org.junit包下。代码已经托管在GitHub上。
为了以后测试方便,自定义了一个JUnit的类库,把几个重要的jar包导在一个类库,
这样,以后的项目工程需要写单元测试,直接导入这个类库,不需要重新导入各种jar包。
自定义类库结构如下:

关于如何自定义类库,Build Path -> Configure Build Path... -> Add Library... -> User Library... -> Next ......,
常规的单元测试,是在工程下新建一个Source Folder和src目录下相同的包名结构,测试A类,就在相对应的包下
创建一个测试类ATest,测试fun方法,就相应的创建测试方法testFun()。本文单纯学习JUnit特性,没有采用这种方式。
ok,废话到此为止,开始测试。文章略长,按需阅读。
断言 - Assertions
在JUnit 之前版本,经常会使用assertTrue,assertEquals,assertNull等断言,根据字面意思就很容易知道函数的用途。
JUnit 4 结合Hamcrest推出更强大的断言AssertThat(),相比于之前的assertXXX,assertThat代码风格将变得统一,更容易维护;
配合Hamcrest的Matchers, 可以写出很多灵活的测试,下面会提到;另一个优点更倾向于英语语法,不像"谓宾主"
(如:assertEquals(9, x)) 语法模式拗口,assertThat使用类型"主谓宾"的语法模式(如:assertThat(x, is(9)),可能是受母语的影响,
这条优点感触不是很深刻; 下面要说的这个优点比较实用,AssertThat测试失败会提供一些可读的描述性错误信息,
而assertXXX不会(当然可以手动去写),assertThat会举例说明; Last but not the least(v~v高考残留的英语记忆),
可发人员可以实现Matcher接口,自定义匹配符,这个功能很强大。
注意:测试的时候需要引入一些类,有些类(Assert, Matchers)比较特殊,采用静态引入的方式,
好处在于可以直接使用这些类的静态方法(assertTure, assertThat),而不用使用类名.方法名的方式。
assertXXX
import static org.junit.Assert.*; import org.junit.Test; /**
* AssertXXX测试
* @author michael
*/
public class AssertTests { @Test
public void testAssertArrayEquals() {
byte[] expected = "trial".getBytes();
byte[] actual = "trial".getBytes();
assertArrayEquals("failure - byte arrays not same", expected, actual);
} @Test
public void testEquals() {
assertEquals("failure - strings are not equal", "text", "text");
} @Test
public void testAssertTrue() {
assertTrue("failure - should be true", true);
} @Test
public void testFalse() {
assertFalse("failure - should be false", false);
} @Test
public void testAssertNotNull() {
assertNotNull("should not be null", new Object());
} @Test
public void testAssetNull() {
assertNull("should be null", null);
} @Test
public void testAssertNotSame() {
assertNotSame("should not be same Object", new Object(), new Object());
} @Test
public void testAssertSame() {
Integer aNumber = Integer.valueOf(985);
assertSame("should be same", aNumber, aNumber);
} }
assertThat
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*; import java.util.Arrays; import org.junit.Test; public class AssertThatTests { //JUnit Matchers assertThat
@Test
public void testAssertThatBothContainsString() {
assertThat("albumen", both(containsString("a")).and(containsString("b")));
} @Test
public void testAssertThathasItemsContainsString() {
assertThat(Arrays.asList("one", "two", "three"), hasItems("one", "three"));
} @Test
public void testAssertThatEveryItemContainsString() {
assertThat(Arrays.asList(new String[] {"fun", "ban", "net"}), everyItem(containsString("n")));
} /**
* Core Hamcrest Matchers with assertThat
* 组合使用多种匹配符
*/
@Test
public void testAssertThatHamcrestCoreMatchers() {
assertThat("good", allOf(equalTo("good"), startsWith("good")));
assertThat("good", not(allOf(equalTo("good"), equalTo("bad"))));
assertThat("good", anyOf(equalTo("good"), equalTo("bad")));
assertThat(3, not(either(equalTo(6)).or(equalTo(9))));
assertThat(new Object(), not(sameInstance(new Object())));
} /**
* Readable failure message
* assertThat会提供可读性的错误信息,assertTrue不会
*/
@Test
public void testFailureMessage() {
String s = "coour";
//assertTrue(s.contains("color") || s.contains("colour"));
assertThat(s, anyOf(containsString("color"), containsString("colour")));
} }
套件测试 - Aggregating tests in Suites
如果你写了一系列的测试类(十几个甚至几十个),你不可能一个一个的去测试,此时,套件测试就会派上用场。
创建一个空类,不需要为这个类定义任何东西,只需要在这个类的头部添加注解@RunWith(Suite.class)。
@Suite.SuiteClasses。在SuiteClasses里添加需要测试的类。创建的这个类只是作为一个载体,承载上面的注解。
import org.junit.runner.RunWith;
import org.junit.runners.Suite; import assertions.AssertTests;
import assertions.AssertThatTests; @RunWith(Suite.class)
@Suite.SuiteClasses({
//添加需要测试的类
AssertTests.class,
AssertThatTests.class // more test classes
}) public class FutureTestSuite { /**
* the class remains empty,
* used only a holder for the above annotations.
*/
}
What's the difference between failure and error in JUnit
顺序测试 - Test Execution Order
顺序测试的应用场景不是很多,当你想让你写的一系列测试方法按照一定的顺序执行才会用到。
添加@FixMethodOrder注解,有三种常用的运行顺序定义在枚举类MethodSorters内。
DEFAULT、JVM、NAME_ASCENDING。
DEFAULT:默认,比较方法名的hashCode值。
JVM:依赖JVM的实现,不同机器上可能有所不同。
NAME_ASCENDING:按照测试函数方法名升序。
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING)
//@FixMethodOrder(MethodSorters.DEFAULT)
//@FixMethodOrder(MethodSorters.JVM)
public class TestMethodOrder { @Test
public void testA() {
System.out.println("first");
} @Test
public void testB() {
System.out.println("second");
} @Test
public void testC() {
System.out.println("third");
} }
异常测试 - Exception Testing
开发者在编写程序时,有些代码可能会抛出异常。
如何测试这些代码是否按照我们预想的抛出异常,此时就需要用到异常测试。
@Test注解有一个可选择的参数expected,用于指定可能抛出的异常。例如:
Expected Exceptions
import java.util.ArrayList;
import org.junit.Test; public class TestException { @SuppressWarnings("unused")
private double result; @Test(expected = ArithmeticException.class)
public void divide() {
result = 1/0;
} /**
* The expected parameter should be used with care.
* The test will pass if any code in the method throws IndexOutOfBoundsException
*/
@Test(expected = IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
} }
不过,expected参数应当谨慎使用,因为,如果测试方法任意一处代码抛出expected指定的异常,
测试都会通过,无法准确定位哪处代码抛出的异常。长远考虑,推荐使用ExpectedException rule。
关于Rule会在另一篇文章中介绍。
ExceptedException rule
上面的测试方法对于测试简单的例子比较适用,但它存在一定的限制,比如开发者无法测试异常信息。
当然JUnit3.x 提供了Try/Catch Idiom可以预测异常和异常信息。JUnit4则提供了ExpectedException rule。
不同的是,JUnit4 expectedMessage除了可以预测可能抛出的异常信息,还可以与Hamcrest的Matchars配合 使用,
编写出更加灵活的测试。例如:
import static org.hamcrest.Matchers.containsString; import java.util.ArrayList;
import java.util.List; import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException; public class TestExceptionRule { //Expected Exception Rule
@Rule
public ExpectedException thrown =ExpectedException.none(); /**
* This rule lets you indicate not only what exception you are expecting,
* but also the exception message you are expecting:
*/
@Test
public void shouldTestExceptionMessage() {
List<Object> list = new ArrayList<Object>(); thrown.expect(IndexOutOfBoundsException.class);
thrown.expectMessage("Index: 0, Size: 0");
thrown.expectMessage(containsString("Size: 0")); list.get(0);
} }
测试忽略 - Ignore tests
如果在某次测试中想要跳过某个测试方法,就使用@Ignore注解。
当然直接注释掉@Test注解同样可以跳过该测试方法,不同的是,
注释掉在测试结果中不会显示,而使用@Ignore会显示该方法被忽略。
import org.junit.Ignore;
import org.junit.Test; public class TestIgnore { @Test
public void testA() {
System.out.println("executed");
} @Ignore
@Test
public void testB() {
System.out.println("ignored");
} }
超时测试 - Timeout for tests
超时测试,顾名思义,测试方法超过指定的时间就会报Errors,注意不是Failures。
Why is JUnit timeout an Error Not Failure
开发人员可以为单独某个方法设置超时时间,也可以为整个测试类设置统一超时时间。
单独为一个方法设置超时时间,单位毫秒
import org.junit.Test;
public class TestTimeout {
@Test(timeout=100)
public void testWithTimeOut() {
for( ; ;) {
}
}
}
为整个类设置超时时间,单位毫秒
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout; public class TestTimeoutRule { public static int n; @Rule
public Timeout globalTimeout = new Timeout(100); @Test
public void testInfiniteLoop1() {
n++;
for( ; ;) { }
} @Test
public void testInfiniteLoop2() {
n++;
for( ; ;) { }
} }
结束语
Keeps the bar green to keep the code clean.
JUnit4单元测试基础篇的更多相关文章
- junit4单元测试基础
导入方法看如下截图就明白了: 新建测试用例 右击包名,点击新建,或者新建里的others,选择JUnit test case,如下图所示: 接下来,给测试类起名字和选择要测试的类,如下图所示: ...
- DDD分层架构之领域实体(基础篇)
DDD分层架构之领域实体(基础篇) 上一篇,我介绍了自己在DDD分层架构方面的一些感想,本文开始介绍领域层的实体,代码主要参考自<领域驱动设计C#2008实现>,另外参考了网上找到的一些示 ...
- python面试题库——1Python基础篇
第一部分 Python基础篇(80题) 为什么学习Python? 语言本身简洁,优美,功能超级强大,跨平台,从桌面应用,web开发,自动化测试运维,爬虫,人工智能,大数据处理都能做 Python和Ja ...
- SpringBoot使用Junit4单元测试
SpringBoot2.0笔记 本篇介绍Springboot单元测试的一些基本操作,有人说一个合格的程序员必须熟练使用单元测试,接下来我们一起在Springboot项目中整合Junit4单元测试. 本 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- SpringBoot图文教程「概念+案例 思维导图」「基础篇上」
有天上飞的概念,就要有落地的实现 概念+代码实现是本文的特点,教程将涵盖完整的图文教程,代码案例 每个知识点配套自测面试题,学完技术自我测试 本文初学向,所以希望文中所有的代码案例都能敲一遍 大哥大姐 ...
- 面试题之第一部分(Python基础篇) 80题
第一部分(python基础篇)80题 为什么学习Python?==*== # 1. python应用于很多领域,比如后端,前端,爬虫,机器学习(人工智能)等方面,几乎能涵盖各个开发语言的领域,同时它相 ...
- Python自动化测试面试题-Python基础篇
目录 Python自动化测试面试题-经验篇 Python自动化测试面试题-用例设计篇 Python自动化测试面试题-Linux篇 Python自动化测试面试题-MySQL篇 Python自动化测试面试 ...
- 十一、Abp vNext 基础篇丨测试
前言 祝大家国庆快乐,本来想国庆之前更新完的,结果没写完,今天把剩下的代码补了一下总算ok了. 本章节也是我们后端日常开发中最重要的一步就是测试,我们经常听到的单元测试.集成测试.UI测试.系统测试, ...
随机推荐
- 读书笔记—CLR via C#章节11-13
前言 这本书这几年零零散散读过两三遍了,作为经典书籍,应该重复读反复读,既然我现在开始写博了,我也准备把以前觉得经典的好书重读细读一遍,并且将笔记整理到博客中,好记性不如烂笔头,同时也在写的过程中也可 ...
- PHP中判断输入验证码是否一致
首先用session将随机生成的验证码的值传到页面,然后获取当前文本框中输入的值 进行对比:代码如下: 生成的随机数,把它传到session里面 <? session_start(); 必 ...
- Eclipse编辑器样式修改
很多的开发工具都可以更改主题样式,但eclipse作为一款影响力巨大的开源开发工具,却没有自带更改样式的功能,这多少令人有点小遗憾.Eclipse 4之后,Eclipse使用者呼声高涨,就有人开始做起 ...
- The initialization of the CRM authentication pipline execution has failed
由于公司电路切换,昨天晚上不得不将服务器暂时关闭.早上重新开机时,发现开发环境连不上了.这可把我急坏了,大家可都等着开发呢. 于是查看服务器错误消息,发现时数据库连接连接不上. The initial ...
- D10
=-=今天被dev-c++坑到死..简直 晚上准备怒装liunx.. T1:数论 一开始碰到的是T1的运算符优先问题吧..maybe..但是我加上括号了还是WA啊..后面把式子拆开写才A了..次奥 附 ...
- usaco1.1.1Your Ride Is Here(入门题)
一下是我很久很久之前刷的题目...随便扔在这里啦.. Description 一个众所周知的事实,在每一慧星后面是一个不明飞行物UFO.这些不明飞行物时常来收集来自在地球上忠诚的支持者.不幸的是,他们 ...
- GCC/G++ 学习笔记
本文是<An introduction to GCC>的学习笔记,记录使用GCC/G++主要的实用技巧,本文讲述的知识基本上摘自本书,附带自己的一些体验.如果想详细查看本书,请戳这里. 一 ...
- 随手复习一下委托:delegate
先骂个街,天儿太闷了…… 随手复习一下委托,delegate 是一种函数指针,是 .net 提供的一种安全的函数指针,翻译的也很贴切,像是委托人,又像代理人,通过“委托”来执行一些函数而不是直接调用它 ...
- JavaScript 跨域方法总结
同源策略 在客户端编程语言中,如javascript和 ActionScript,同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义.同源策略规定跨域之间的脚本是隔离的,一个域的脚 ...
- IceMx.Mvc 我的js MVC 框架 开篇
开篇 这篇文章是后补的,前端时间想写一些对于js开发的一些理解,就直接写了,后来发现很唐突,所以今天在这里补一个开篇. 我的js Mvc 框架 基于实用设计,过分设计等于没设计.本着简单的原则,它只实 ...