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测试.系统测试, ...
随机推荐
- Jqury笔记
1. --------------- -var aa = new Array(); aa.push(1); alert(aa[0]); var aa=[];也表示一个数组: ------------ ...
- OpenGL Development Cookbook chapter7部分翻译
让我们通过以下简单步骤开始我们的配方: 1.通过读取外部的体数据文件,并通过该加载数据集数据转换成一个OpenGL纹理.也使硬件的mipmap生成.通常情况下,从使用一个横截面中获得的体积数据文件存储 ...
- 如何在ubuntu 12.04下搭建Python Django环境
1. 检查python是否安装:直接在shell里输入python,如果已经安装了python,即可进入python bash,并看到版本号(如Python 2.7.3) ——在ubuntu中pyth ...
- MVC Filter 实现方式和作用范围控制
Asp.Net MVC Filter 实现方式和作用范围控制 MVC中的Filte 简单又优雅的实现了AOP ,在日志,权限,缓存和异常处理等方面用的比较多.但本文不是讨论Filter这些功能点,而是 ...
- Euclid Problem - PC110703
欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/uva10104.html 原创:Eucl ...
- ASP.Net页面传值比较
ASP.Net页面传值比较 作为一个ASP.Net程序员,尤其是搞B/S开发的,对于不同页面之间变量值的传递用的非常广泛,而掌握不同方式之间的区别和特点也就很有必要.本文将针对这一知识点做一个简单 ...
- NUnit详细使用方法
http://www.ltesting.net/ceshi/open/kydycsgj/nunit/ http://nunit.org/index.php?p=download NUnit详细使用方法 ...
- ASP.NET WEB API构建基于REST风格
使用ASP.NET WEB API构建基于REST风格的服务实战系列教程[开篇] 最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http ...
- twitter 授权过程
转自:http://blog.csdn.net/yangjian8915/article/details/11816669 官方的流程图如下: 下面开始一步步讲解,如何获取最终的access_toke ...
- C# 利用反射动态创建对象——带参数的构造函数和String类型
C# 利用反射动态创建对象——带参数的构造函数和String类型 最近笔者有一个想法需要利用反射动态创建对象(如string,int,float,bool,以及自定义类等)来实现,一直感觉反射用不好, ...