(一)JUnit介绍

1.什么是单元测试?

单元测试负责对最小的软件设计单元(模块)进行验证,根据软件设计文档中对模块功能的描述,对重要的程序分支进行测试并发现错误。

2.什么是单元测试框架?

对于单元测试框架来讲,它主要完成以下几件事。

提供用例组织与执行:测试用例只有几条时,可以不考虑用例组织,但是用例达到成百上千时,大量的测试用例堆砌在一起,就产生了扩展性与维护性等问题

提供丰富的断言方法:不论是功能测试,还是单元测试,在用例执行完之后都需要将实际结果与预期结果相比较(断言),从而断定用例是否执行通过。单元测试框架一般提供丰富的断言方法。例如:判断相等/不等、包含/不包含、True/False的断言方法等

提供丰富的日志:当测试用例执行失败时能抛出清晰的失败原因,当所有用例执行完成后能提供丰富的执行结果。例如,总执行时间、失败用例数、成功用例数等。

从这些特性来看单元测试框架的作用是:帮助我们更自动化完成测试,所以,它是自动化测试的基础。

3.什么是JUnit?

Junit官网:http://junit.org/

JUnit是一个编写可重复测试的简单框架。它是单元测试框架的xUnit架构的一个实例。

JUnit单元测试好处:测试时可以给每个方法添加一个@Test,这样就可以不在main方法中调用改来改去。(方法加了@Test可直接运行,可以不定义主方法就可以执行了)

给一个方法单元测试:

1.给方法加@Test

2.导入junit依赖环境

或者【Maven安装Junit】(具体操作参加后续章节内容)

然后就可以点左边的绿色按钮单个执行方法了。

如果执行,下面显示绿色代表成功,红色代表失败(一般都是有异常)

单元测试不依赖以System.out.println();一般用断言操作(此处简述,详细代码叙述参考后续JUnit断言方法部分的内容)。

断言就是你可能某个方法写错(并不指的是真实的错误,有可能就是跟你预期不符合而已),但是Junit

还是执行绿色的如下:

importorg.junit.Test;

public class Junit_test {

public static void main(String[] args) {

}

public static int add(int a,int b){

return a-b;

}

@Test

public void test(){

int result=add(1,2);

System.out.println(result); //-1

}

}

就是你调用add方法(但是返回写为了-号,而不是+号),期待返回3,但是返回-1,这就是跟你的预期不符了,但这是Junit测试还是绿色,所以所不能用输出来评判对不对;

所以我们应该用断言:

Assert.assertEquals(期望的结果,运算的结果);(如果不符合你的预期,下面就会报红色)(assertEquals是方法重载得选对参数)

importorg.junit.Assert;

importorg.junit.Test;

public class Junit_test {

public static void main(String[] args) {

}

public static int add(int a,int b){

return a-b;

}

@Test

public void test(){

int result=add(1,2);

Assert.assertEquals(3,result);

}

}

这由于预期是3,而实际是-1所以报错(爆红)。

(二)JUnit安装

Junit目前分两个版本,Junit4和Junit5,本系列教程打算从Junit4开始介绍,最后,再介绍Junit5有哪些新特性

1.IntelliJIDEA安装Junit

Java开发的同学,推荐使用IntelliJIDEA,推荐阅读《IntelliJIDEA教程》。

1、下载junit-4.12.jar文件:https://github.com/junit-team/junit4/releases

2、打开IntelliJIDEA,菜单栏:File菜单–>PorjectStructure选项–>Dependencies标签–>点击“+”号–>Library…–>Java。选择下载的junit-4.12.jar进行添加。

3、以同样的方式下载和导入hamcrest:https://github.com/hamcrest/JavaHamcrest/releases,否则,你将无法运行Junit单元测试。

2.Maven安装Junit

相比较而言,Maven的安装要简单很多,打开你Maven项目中的pom.xml文件,添加如下配置:

junit

junit

4.12

test

3.IDEA安装Junit插件

idea中需要下载的单元测试插件,单击File ,然后找到Settings进行设置 , 如图找到插件(Junit Generator)

单击进行安装,安装完如下图二

(三)JUnit编写单元测试

1.编写单元测试

创建JunitDemo类,编写第一个单元测试用例。

importorg.junit.Test;

importstaticorg.junit.Assert.assertEquals;

publicclassJunitDemo{

@Test

publicvoidmyFirstTest(){

assertEquals(2+2,4);

}

}

@Test用来注释一个普通的方法为一条测试用例。

assertEquals()方法用于断言两个值是否相关。

importorg.junit.Test;

importstaticorg.junit.Assert.assertEquals;

publicclassJunitDemo{

@Test

publicvoidmyFirstTest(){

assertEquals(2+2,5);

}

}

通过测试可以更好的观察代码的运行效果,还可以看这个方法运行了多少时间。当在开发过程中,需要对某些业务进行性能调优的时候,不知道哪个方法是最好的,就可以编写测试类代码通过运行效果的时间上去对比,得到时间复杂度,消耗的时间,从而得到最优。

2.测试功能模块

创建一个被测试类:Count,代码如下:

publicclassCount{

/**

*计算并返回两个参数的和

*/

publicintadd(intx,inty){

returnx+y;

}

}

Count类的实现非常简单,看注释就可以了。

接下来,创建CountTest类,用于测试Count类。

importstaticorg.junit.Assert.assertEquals;

importorg.junit.Test;

publicclassCountTest{

@Test

publicvoidtestAdd(){

Countcount=newCount();

intresult=count.add(2,2);

assertEquals(result,4);

}

}

new出Count类,调用add()方法并传参,通过assertEquals()断言返回结果。

恭喜!你已经会编写单元测试了。

(四)JUnit注解

1.JUnit注解(标签)

JUnit注解说明:

注解说明@Test:此处编写测试用例的方法,标识一条测试用例。@Test(timeout=xxx)设置当前的测试方法在一定时间内运行完,否则返回错误@Test(expected=Exception.class)设置当前的测试方法是否有异常抛出,异常类型为Exception.class@Ignore:注释掉一个测试类或方法,该方法或类不会被执行@Before:每一个测试方法之前运行。@After:每一个测试方法之后运行。@BefreClass所有测试开始之前运行。在一个类执行之前执行一次@AfterClass所有测试结果之后运行。在一个类执行之后执行一次

2.例子

创建被测试类Count

public class Count {

/**

* 计算并返回两个参数的和

*/

public int add(int x, int y) {

return x + y;

}

/**

* 计算并返回两个数相除的结果

*/

public int division(int a, int b) {

return a / b;

}

}

创建测试类CountTest.

import org.junit.After;

import org.junit.Before;

import org.junit.Ignore;

import org.junit.Test;

import staticorg.junit.Assert.assertEquals;

public class CountTest {

@Before

public void init() {

System.out.println("init...");

}

@After

public void close() {

System.out.println("close...");

}

//验证超时

@Test(timeout = 100)

public void testAdd() throws InterruptedException {

Thread.sleep(101);

new Count().add(1, 1);

}

//验证抛出异常

@Test(expected = ArithmeticException.class)

public void testDivision() {

new Count().division(8, 0);

}

//跳过该条用例

@Ignore

@Test

public void testAdd2() {

int result = Count.add(2, 2);

assertEquals(result, 5);

}

}

虽然爆红,但是该输出的输出,该关闭的关闭

(五)JUnit注解之Fixture

继续介绍JUnit的注解

什么是Fixture

TestFixture是指一个测试运行所需的固定环境,准确的定义:

ThetestfixtureiseverythingweneedtohaveinplacetoexercisetheSUT

在进行测试时,我们通常需要把环境设置成已知状态(如创建对象、获取资源等)来创建测试,每次测试开始时都处于一个固定的初始状态;测试结果后需要将测试状态还原,所以,测试执行所需要的固定环境称为TestFixture。

JUnit中的Fixture

被测试类同样使用上一小节的Count,创建TestFixture测试类。

importstaticorg.junit.Assert.*;

importorg.junit.*;

publicclassTestFixture{

//在当前测试类开始时运行。

@BeforeClass

publicstaticvoidbeforeClass(){

System.out.println("-------------------beforeClass");

}

//在当前测试类结束时运行。

@AfterClass

publicstaticvoidafterClass(){

System.out.println("-------------------afterClass");

}

//每个测试方法运行之前运行

@Before

publicvoidbefore(){

System.out.println("=====before");

}

//每个测试方法运行之后运行

@After

publicvoidafter(){

System.out.println("=====after");

}

@Test

publicvoidtestAdd1(){

intresult=newCount().add(5,3);

assertEquals(8,result);

System.out.println("testRuntestadd1");

}

@Test

publicvoidtestAdd2(){

intresult=newCount().add(15,13);

assertEquals(28,result);

System.out.println("testRuntestadd2");

}

}

代码中的注释已经对@BeforeClass、@AfterClass、@Before、@After做了说明。

至于什么时候会用到这些方法跟你具体的业务用例有关,如果是WebUI自动化测试,可以把浏览器驱动的定义放到@Before中,浏览器的关闭放到@After中。

运行结果如下:

(六)JUnit用例执行顺序

在运行测试的过程中,有时候需要控制用例的执行顺序。

@FixMethodOrder

JUnit通过@FixMethodOrder注解来控制测试方法的执行顺序的。@FixMethodOrder注解的参数是org.junit.runners.MethodSorters对象,在枚举类org.junit.runners.MethodSorters中定义了如下三种顺序类型:

MethodSorters.JVM

LeavesthetestmethodsintheorderreturnedbytheJVM.NotethattheorderfromtheJVMmayvaryfromruntorun(按照JVM得到的方法顺序,也就是代码中定义的方法顺序)

MethodSorters.DEFAULT(默认的顺序)

Sortsthetestmethodsinadeterministic,butnotpredictable,order()(以确定但不可预期的顺序执行)

MethodSorters.NAME_ASCENDING

Sortsthetestmethodsbythemethodname,inlexicographicorder,withMethod.toString()usedasatiebreaker(按方法名字母顺序执行)

例子

具体如何使用,看例子,创建TestRunSequence测试类。

importorg.junit.FixMethodOrder;

importorg.junit.Test;

importorg.junit.runners.MethodSorters;

//按字母顺序执行

@FixMethodOrder(MethodSorters.NAME_ASCENDING)

publicclassTestRunSequence{

@Test

publicvoidTestCase1(){

System.out.println("TestCase1");

}

@Test

publicvoidTestCase2(){

System.out.println("TestCase2");

}

@Test

publicvoidTestAa(){

System.out.println("TestAa");

}

}

MethodSorters.NAME_ASCENDING设置按字母的顺序执行,所以,TestAa()先被执行,虽然它在代码中是最后一条用例。

运行结果如下:

(七)JUnit断言方法

JUnit断言方法

断言一旦失败,后面的语句将不会被执行。

**断言(assertion)**是一种在程序中的一阶逻辑(如:一个结果为真或假的逻辑判断式),目的为了表示与验证软件开发者预期的结果——当程序执行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止执行,并给出错误信息。

JUnit为我们提供了一些辅助函数,他们用来帮助我们确定被测试的方法是否按照预期的效果正常工作,通常,把这些辅助函数称为断言。下面我们来介绍一下JUnit的各种断言。

Junit 4 断言方法允许检查测试方法的期望结果值和真实返回值。Junit的org.junit.Assert类提供了各种断言方法来写junit测试。这些方法被用来检查方法的真实结果值和期望值。下列一些有用的断言方法列表:

汇总(部分断言需要补全小节内容)

方法说明assertArrayEquals(expecteds,actuals)查看两个数组是否相等。assertEquals(expected,actual)查看两个对象是否相等。类似于字符串比较使用的equals()方法。assertNotEquals(first,second)查看两个对象是否不相等。assertNull(object)查看对象是否为空。assertNotNull(object)查看对象是否不为空。assertSame(expected,actual)查看两个对象的引用是否相等。类似于使用“==”比较两个对象。assertNotSame(unexpected,actual)查看两个对象的引用是否不相等。类似于使用“!=”比较两个对象。assertTrue(condition)查看运行结果是否为true。assertFalse(condition)查看运行结果是否为false。assertThat(actual,matcher)查看实际值是否满足指定的条件。fail()让测试失败。

assertEquals

函数原型:assertEquals([String message],expected,actual)

参数说明:

message是个可选的消息,假如提供,将会在发生错误时报告这个消息。

expected是期望值,通常都是用户指定的内容。

actual是被测试的代码返回的实际值。

例:assertEquals("equals","1","1");

函数原型:assertEquals([String message],expected,actual,tolerance)

参数说明:

message是个可选的消息,假如提供,将会在发生错误时报告这个消息。

expected是期望值,通常都是用户指定的内容。

actual是被测试的代码返回的实际值。

tolerance是误差参数,参加比较的两个浮点数在这个误差之内则会被认为是相等的。

例:assertEquals ("yes",5.8,11.0/2.0,0.5);

assertNull 和assertNotNull

函数原型:assertNull([String message],Object object)

参数说明:

message是个可选的消息,假如提供,将会在发生错误时报告这个消息。

object是待验证的对象。

该断言用来验证给定的对象是否为null,假如不为null,则验证失败。相应地,还存在能够验证非null的断言:

函数原型:assertNotNull([String message],Object object)

该断言用来验证给定的对象是否为非null,假如为null,则验证失败。

例:assertNull("null",null);

assertNotNull("not null",newString());

assertSame 和assertNotSame

函数原型:assertSame ([String message], expected,actual)

参数说明:

message是个可选的消息,假如提供,将会在发生错误时报告这个消息。

expected是期望值。

actual是被测试的代码返回的实际值。

该断言用来验证expected参数和actual参数所引用的是否是同一个对象,假如不是,则验证失败。相应地,也存在验证不是同一个对象的断言:

函数原型:assertNotSame ([String message], expected,actual)

该断言用来验证expected参数和actual参数所引用的是否是不同对象,假如所引用的对象相同,则验证失败。

例:assertSame("same",2,4-2);

assertNotSame("not same",2,4-3);

assertTrue 和 assertFalse

函数原型:assertTrue ([String message],Boolean condition)

参数说明:

message是个可选的消息,假如提供,将会在发生错误时报告这个消息。

condition是待验证的布尔型值。

该断言用来验证给定的布尔型值是否为真,假如结果为假,则验证失败。当然,更有验证为假的测试条件:

函数原型:assertFalse([String message],Boolean condition)

该断言用来验证给定的布尔型值是否为假,假如结果为真,则验证失败。

例:assertTrue("true",1==1);

assertFalse("false",2==1);

Fail

函数原型:Fail([String message])

参数说明:

message是个可选的消息,假如提供,将会在发生错误时报告这个消息。

该断言会使测试立即失败,通常用在测试不能达到的分支上(如异常)。

assertThat

assertThat介绍

JUnit 4 结合 Hamcrest 提供了一个全新的断言语法——assertThat。程序员可以只使用 assertThat 一个断言语句,结合 Hamcrest 提供的匹配符,就可以表达全部的测试思想

一般匹配符断言

方法介绍assertThat(“myValue”, allOf(startsWith(“my“), containsString(“Val“)))allOf匹配符表明如果接下来的所有条件必须都成立测试才通过,相当于“与”(&&)assertThat(“myValue“, anyOf(startsWith(“foo“), containsString(“Val“)))anyOf匹配符表明如果接下来的所有条件只要有一个成立则测试通过,相当于“或”(assertThat(“myValue“, anything())anything匹配符表明无论什么条件,永远为trueassertThat(“myValue“, is(“myValue“) )is匹配符表明如果前面待测的值等于后面给出的值,则测试通过assertThat(“myValue“, not(“foo“))not匹配符和is匹配符正好相反,表明如果前面待测的值不等于后面给出的值,则测试通过

字符串相关匹配符

方法介绍assertThat(“myStringOfNote“, containsString(“ring“))containsString匹配符表明如果测试的字符串包含子字符串则测试通过assertThat(“myStringOfNote“, endsWith(“Note“))endsWith匹配符表明如果测试的字符串以子字符串结尾则测试通过assertThat(“myStringOfNote“, startsWith(“my“))startsWith匹配符表明如果测试的字符串以子字符串开始则测试通过assertThat(“foo“, equalTo(“foo“))equalTo匹配符表明如果测试的数据等于则测试通过,equalTo可以测试数值之间,字符串之间和对象之间是否相等,相当于Object的equals方法assertThat(“Foo“, equalToIgnoringCase(“FOO“))equalToIgnoringCase匹配符表明如果测试的字符串在忽略大小写的情况下等于则测试通过assertThat(“my\tfoo bar“, equalToIgnoringWhiteSpace(“my foo bar“)equalToIgnoringWhiteSpace匹配符表明如果测试的字符串在忽略头尾的任意个空格的情况下等于则测试通过,注意:字符串中的空格不能被忽略

数值相关匹配符

方法介绍assertThat(1.03, is(closeTo(1.0, 0.03)))closeTo匹配符表明如果所测试的浮点型数在1.0±0.03范围之内则测试通过assertThat(2, greaterThan(1))greaterThan匹配符表明如果所测试的数值大于1则测试通过assertThat(1, lessThan(2))lessThan匹配符表明如果所测试的数值小于2则测试通过assertThat(1, greaterThanOrEqualTo(1))greaterThanOrEqualTo匹配符表明如果所测试的数值大于等于1则测试通过assertThat(1, lessThanOrEqualTo(1))lessThanOrEqualTo匹配符表明如果所测试的数值小于等于1则测试通过

集合相关匹配符

方法介绍assertThat(myMap, hasEntry(“bar“, “foo“))hasEntry匹配符表明如果测试的Map对象含有一个键值为"bar"对应元素值为"foo"的Entry项则测试通过ssertThat(Arrays.asList(“foo“, “bar“), hasItem(startsWith(“ba“)))hasItem匹配符表明如果测试的迭代对象含有元素以ba开头项则测试通过assertThat(myMap, hasKey(“bar“))hasKey匹配符表明如果测试的**Map对象含有键值“bar”**则测试通过assertThat(myMap, hasValue(“foo“))hasValue匹配符表明如果测试的**Map对象含有元素值“foo”**则测试通过

例子-assertTrue

关于断言方法,我们前面用得最多的是assertEquals,用于断言两个对象是否相等。这里再介绍一个assertTrue的使用。

创建AssertTest测试类(包了含被测试方法):

import org.junit.*;

import static org.junit.Assert.*;

public class AssertTest {

/**

* 判断一个数是否为素数

*/

public static Boolean Prime(int n) {

for (int i = 2; i < Math.sqrt(n); i++) {

if (n % i == 0) {

return false;

}

}

return true;

}

@Test

public void testPrime() {

int n = 7;

assertTrue(AssertTest.Prime(n));

}

}

Prime()方法用于判断一个数是否为素数(只能被1和它本身整除的数),并返回True或False,在测试用例中通过assertTrue来断言结果。

例子2 – 多个断言的示例

import org.junit.Test;

import org.junit.jupiter.api.DisplayName;

import java.io.File;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.LinkedList;

import java.util.List;

import staticorg.junit.Assert.assertArrayEquals;

import static org.junit.Assert.assertEquals;

import static org.junit.Assert.assertFalse;

import staticorg.junit.Assert.assertNotEquals;

import static org.junit.Assert.assertTrue;

import static org.junit.Assert.fail;

import staticorg.junit.jupiter.api.Assertions.assertNotNull;

import staticorg.junit.jupiter.api.Assertions.assertNotSame;

import staticorg.junit.jupiter.api.Assertions.assertNull;

import staticorg.junit.jupiter.api.Assertions.assertSame;

import staticorg.junit.jupiter.api.Assertions.*;

/**

*@author javatutorials.co.in

*/

public class AssertionsTest {

@Test

@DisplayName("assertArrayEquals Examples")

public void test_assertArrayEquals() {

String[] s1 = {"A", "B"};

String[] s2 = {"A", "B"};

assertArrayEquals(s1, s2);

assertArrayEquals("My Custom Failure Message", s1, s2);

}

@Test

@DisplayName("assertIterableEquals Examples")

public void test_assertIterableEquals() {

List l1 = newArrayList<>(Arrays.asList("A", "B"));

List l2 = newLinkedList<>(Arrays.asList("A", "B"));

assertIterableEquals(l1, l2);

assertIterableEquals(l1, l2, "Custom Failure Message");

}

@Test

public void testAssertEqualsLong() {

long long1 = 2;

long long2 = 2;

assertEquals(long1, long2);

}

@Test

public void testAssertEqualsDouble() {

// test case is successfull as double1 and double 2

// differ by 0.001 which is less than our specified delta

double double1 = 1.236;

double double2 = 1.237;

double delta = 0.002;

assertEquals(double1, double2, delta);

}

@Test

@DisplayName("assertEquals Examples")

public void test_assertEquals() {

assertEquals(10, 10);

assertEquals("assertEquals Failure Message", true, true);

assertEquals("Hi", new String("Hi"));

assertEquals(new File("test"), new File("test"));

}

@Test

@DisplayName("assertNotEquals Examples")

public void test_assertNotEquals() {

assertNotEquals(10, 100);

assertNotEquals("assertEquals Failure Message", true, false);

assertNotEquals("Hi", new String("Hello"));

assertNotEquals(new File("test"), newFile("test1"));

}

@Test

public void testAssertNull() {

String str = null;

assertNull(str);

}

@Test

public void testAssertNotNull() {

String str = "hello Java!!";

assertNotNull(str);

}

@Test

@DisplayName("assertNull Examples")

publicvoid test_assertNull() {

assertNull(null);

//assertNull(new Object(), "assertNull Fail Message");

}

@Test

@DisplayName("assertNotNull Examples")

public void test_assertNotNull() {

assertNotNull(new Object());

//assertNotNull(null, "assertNotNull Fail Message");

}

@Test

public void testAssertSame() {

String str1 = "hello world!!";

String str2 = "hello world!!";

assertSame(str2, str1);

}

@Test

public void testAssertNotSame() {

String str1 = "hello world!!";

String str3 = "hello Java!!";

assertNotSame(str1, str3);

}

@Test

@DisplayName("assertSame Examples")

public void test_assertSame() {

assertSame("Hi", "Hi");

// this will fail

// assertSame("Hi", new String("Hi"), "MyFailure Message");

}

@Test

@DisplayName("assertNotSame Examples")

public void test_assertNotSame() {

assertNotSame("Hi", "Hello");

// this will fail

//assertNotSame("Hi", "Hi", "assertNotSameFailure Message");

}

@Test

public void testAssertTrue() {

List list = new ArrayList();

assertTrue(list.isEmpty());

}

@Test

public void testAssertFalse() {

List list = new ArrayList();

list.add("hello");

assertFalse(list.isEmpty());

}

@Test

@DisplayName("assertTrue Examples")

public void test_assertTrue() {

assertTrue(3 > 0);

assertTrue("assertTrue fail message", 3 > 0);

}

@Test

@DisplayName("assertFalse Examples")

public void test_assertFalse() {

assertFalse(3 < 0);

assertFalse("assertFalse fail message", 3 < 0);

}

@Test

@DisplayName("This will Fail, don't worry!")

public void test_fail() {

fail();

fail("Not yet implemented");

}

@Test

@DisplayName("assertThrows Examples")

public void test_assertThrows() {

assertThrows(RuntimeException.class, () -> {

throw new RuntimeException();

});

assertThrows(Exception.class, () -> {

throw new RuntimeException();

});

// this will fail

// assertThrows(IOException.class, () -> {throw newRuntimeException();});

// assertThrows(IOException.class, () -> {throw newRuntimeException();}, "assertThrows Failure Message");

}

}

例子3-assertThat

Cs.java

importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;

public class Cs{

public int add(int a, int b) {

return a + b;

}

public double div(double a, double b) {

return a / b;

}

public String getName(String name) {

return name;

}

public List getList(Stringitem) {

List l = newArrayList();

l.add(item);

return l;

}

public MapgetMap(String key, String value) {

Map m = newHashMap();

m.put(key, value);

return m;

}

}

CsTest.java

importorg.junit.Test;

importjava.util.List;

importjava.util.Map;

import staticorg.hamcrest.MatcherAssert.assertThat;

import staticorg.hamcrest.Matchers.*;

public classCsTest {

@Test

public void testAdd() {

//一般匹配符

int s = new Cs().add(1, 1);

//allOf:所有条件必须都成立,测试才通过

assertThat(s, allOf(greaterThan(1),lessThan(3)));

//anyOf:只要有一个条件成立,测试就通过

assertThat(s, anyOf(greaterThan(1),lessThan(1)));

//anything:无论什么条件,测试都通过

assertThat(s, anything());

//is:变量的值等于指定值时,测试通过

assertThat(s, is(2));

//not:和is相反,变量的值不等于指定值时,测试通过

assertThat(s, not(1));

//数值匹配符

double d = new Cs().div(10, 3);

//closeTo:浮点型变量的值在3.0±0.5范围内,测试通过

assertThat(d, closeTo(3.0, 0.5));

//greaterThan:变量的值大于指定值时,测试通过

assertThat(d, greaterThan(3.0));

//lessThan:变量的值小于指定值时,测试通过

assertThat(d, lessThan(3.5));

//greaterThanOrEuqalTo:变量的值大于等于指定值时,测试通过

assertThat(d,greaterThanOrEqualTo(3.3));

//lessThanOrEqualTo:变量的值小于等于指定值时,测试通过

assertThat(d, lessThanOrEqualTo(3.4));

//字符串匹配符

String n = new Cs().getName("Magci");

//containsString:字符串变量中包含指定字符串时,测试通过

assertThat(n,containsString("ci"));

//startsWith:字符串变量以指定字符串开头时,测试通过

assertThat(n,startsWith("Ma"));

//endsWith:字符串变量以指定字符串结尾时,测试通过

assertThat(n, endsWith("i"));

//euqalTo:字符串变量等于指定字符串时,测试通过

assertThat(n,equalTo("Magci"));

//equalToIgnoringCase:字符串变量在忽略大小写的情况下等于指定字符串时,测试通过

assertThat(n,equalToIgnoringCase("magci"));

//equalToIgnoringWhiteSpace:字符串变量在忽略头尾任意空格的情况下等于指定字符串时,测试通过

assertThat(n,equalToIgnoringWhiteSpace(" Magci "));

//集合匹配符

List l = newCs().getList("Magci");

//hasItem:Iterable变量中含有指定元素时,测试通过

assertThat(l,hasItem("Magci"));

Map m = newCs().getMap("mgc", "Magci");

//hasEntry:Map变量中含有指定键值对时,测试通过

assertThat(m, hasEntry("mgc","Magci"));

//hasKey:Map变量中含有指定键时,测试通过

assertThat(m, hasKey("mgc"));

//hasValue:Map变量中含有指定值时,测试通过

assertThat(m, hasValue("Magci"));

}

}

(八)JUnit测试批量运行

前面测试用例的运行主要针对单个测试类进行的,当然,在IntelliJIDEA中也可以选择单个的方法执行。那如果我们想运行所有的用例的文件呢?

IntelliJIDEA中设置运行

设置

在IntelliJIDEA中,菜单栏:Run菜单–>EditConfigurations…选项。

在Junit目录下,选择任意一个用例文件。

TestKind:选择用例的运行类型/级别。

packages:选择用例运行的目录,即你的测试用例目录。

设置完成后,点击“OK”按钮。

运行

点击IntelliJIDEA工具栏上的运行按钮,来运行test目录下的所有用例。

运行结果:

通过测试套件运行

这种方法引入一种 “测试套件” 的概念,JUnit 提供了一种批量运行测试类的方法,叫测试套件。

测试套件的写法需要遵循以下原则:

创建一个空类作为测试套件的入口;

使用注解 org.junit.runner.RunWith 和 org.junit.runners.Suite.SuitClasses 修饰这个空类。

将 org.junit.runners.Suite 作为参数传入给注解 RunWith,以提示 JUnit 为此类测试使用套件运行器执行。

将需要放入此测试套件的测试类组成数组作为注解SuiteClasses 的参数。

保证这个空类使用public修饰,而且存在公开的不带任何参数的构造函数。

单独创建一个测试类 runAllTest .

package test;

importorg.junit.runner.RunWith;

importorg.junit.runners.Suite;

import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)

@SuiteClasses({

CountTest.class,

TestFixture.class,

AssertTest.class,

TestRunSequence.class,

})

public classrunAllTest {

}

把需要运行的测试类放到 SuiteClasses 中,运行runAllTest 测试类,即可批量执行测试用例。

(九)JUnit5 介绍与安装

官方网址:http://junit.org/junit5/

Junit5 已经不算是新的版本了,2016 年推出非正式版,相比较 JUnit4 安装和使用都有一定的差异。

JUnit5 介绍

The new major version of the programmer-friendly testingframework for Java 8

一个新的重要版本,程序员更友好的测试框架,基于 Java8。

关于

JUnit5 是 JUnit 的下一代。我们的目标是为 JVM 上的开发人员端测试创建一个最新的基础。这包括针对 Java 8 及以上,以及使许多不同风格的测试。

Junit5 组成

先看来个公式:

JUnit 5 = JUnitPlatform + JUnit Jupiter + JUnit Vintage

这看上去比 Junit4 复杂,实际上在导入包时也会复杂一些。

JUnitPlatform 是在JVM上启动测试框架的基础。

JUnitJupiter 是JUnit5扩展的新的编程模型和扩展模型,用来编写测试用例。Jupiter子项目为在平台上运行Jupiter的测试提供了一个TestEngine(测试引擎)。

JUnitVintage 提供了一个在平台上运行JUnit3 和JUnit4 的TestEngine 。

Maven 安装

首先,你需要通过 IntelliJ IDEA创建一个 Maven 项目,IntelliJ IDEA 集成的有 Maven,所以,你很容易做到这一点。通过 Maven 的 pom.xml 文件,添加 Junit5 。

pom.xml 文件配置如下:

org.junit.platform

junit-platform-launcher

1.0.1

test

org.junit.jupiter

junit-jupiter-engine

5.0.1

test

org.junit.vintage

junit-vintage-engine

4.12.1

test

(十)JUnit5 创建测试

创建测试用例

我在 IntelliJ IDEA 中创建的 Maven 项目,目录结构如下:

SHAPE \* MERGEFORMAT

在 test.java 目录下创建一个 FistJUnit5Tests 类。代码如下:

importorg.junit.jupiter.api.Test;

import staticorg.junit.jupiter.api.Assertions.assertEquals;

class FirstJUnit5Tests {

@Test

void myFirstTest() {

assertEquals(2, 1 + 1);

}

}

明显看出和 Junit4 还是有些不同的。

首先,导入测试测试注解(@Test)和断言方法(assertEquals)的路径不同。

其次,不需要手动把测试和测试方法声明为 public 了。

(十一)JUnit5 新的用法

创建 JUnit5NewTests 测试类。

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.*;

class JUnit5NewTests {

@BeforeEach

@DisplayName("每条用例开始时执行")

void start(){

}

@AfterEach

@DisplayName("每条用例结束时执行")

void end(){

}

@Test

void myFirstTest() {

assertEquals(2, 1+ 1);

}

@Test

@DisplayName("描述测试用例╯°□°)╯")

voidtestWithDisplayName() {

}

@Test

@Disabled("这条用例暂时跑不过,忽略!")

void myFailTest(){

assertEquals(1,2);

}

@Test

@DisplayName("运行一组断言")

public voidassertAllCase() {

assertAll("groupAssert",

() ->assertEquals(2, 1 + 1),

() ->assertTrue(1 > 0)

);

}

@Test

@DisplayName("依赖注入1")

public voidtestInfo(final TestInfo testInfo) {

System.out.println(testInfo.getDisplayName());

}

@Test

@DisplayName("依赖注入2")

public voidtestReporter(final TestReporter testReporter) {

testReporter.publishEntry("name", "Alex");

}

}

用法都已经通过测试用例的 @DisplayName 进行了说明,这里不再解释。

运行结果如下:

(十二)补充:JUnit 注解之Rule

一个JUnit Rule就是一个实现了TestRule的类,这些类的作用类似于 @Before、@After,是用来在每个测试方法的执行前后执行一些代码的一个方法。 那为什么不直接用这些 @Before、@After呢?这是因为它们都只能作用于一个类,如果同一个setup需要在两个类里面同时使用,那么你就要在两个测试类里面定义相同的@Before方法,然后里面写相同的代码,这就造成了代码重复。

此外,JUnit Rule还能做一些 @Before、@After这些注解做不到的事情,那就是他们可以动态的获取将要运行的测试类、测试方法的信息。

使用框架自带的Rule

除了增加Rule特性,新版JUnit还添加了很多核心Rule

TemporaryFolder:测试可以创建文件与目录并且会在测试运行结束后将其删除。这对于那些与文件系统打交道且独立运行的测试来说很有用。

ExternalResource:这是一种资源使用模式,它会提前建立好资源并且会在测试结束后将其销毁。这对于那些使用socket、嵌入式服务器等资源的测试来说很有用。

ErrorCollector:可以让测试在失败后继续运行并在测试结束时报告所有错误。这对于那些需要验证大量独立条件的测试来说很有用(尽管这本身可能是个“test smell”)。

ExpectedException:可以在测试中指定期望的异常类型与消息。

Timeout:为类中的所有测试应用相同的超时时间。

例如,TimeOut这个Rule的使用。

import org.junit.Rule;

import org.junit.Test;

import org.junit.rules.Timeout;

public class RuleTestDemo {

//使用Timeout这个Rule

@Rule

public Timeout timeout= new Timeout(1000);

@Test

public voidtestMethod1() throws Exception {

Thread.sleep(1001);

}

@Test

public voidtestMethod2() throws Exception {

Thread.sleep(999);

}

}

使用JUnit所提供的Timeout类,该类用于控制测试用例的执行超时时间。这里设置为1秒,当用例执行超过1秒则失败。接下来分别在 testMethod1和testMethod2两个用例中使用sleep()方法来控制用例的执行时间,显然testMethod1超过1秒,则运行失败。

自定义的Rule(没跑通)

除了可以使用JUnit框架自带的Rule,还可以根据自己的需求自定义Rule。简单来说,自定义一个Rule就是implement一个TestRule 接口,并实现apply()方法。该方法需要返回一个Statement对象。例子如下:

import org.junit.rules.TestRule;

import org.junit.runner.Description;

import org.junit.runners.model.Statement;

public class MethodNameRule implementsTestRule {

public Statement apply(final Statement base, final Descriptiondescription) {

return new Statement() {

@Override

public void evaluate() throws Throwable {

//在测试方法运行之前做一些事情,在base.evaluate()之前

String className =description.getClassName();

String methodName =description.getMethodName();

base.evaluate(); //运行测试方法

//在测试方法运行之后做一些事情,在base.evaluate()之后

System.out.println("Classname:"+className+", method name: "+methodName);

}

};

}

}

这里实现的功能是在每次测试用例运行之后,打印当前测试用例的类名和方法名。 在上面的例子中添加这里定义的MethodNameRule。

……

public class RuleTestDemo {

//使用Timeout这个Rule

@Rule

public Timeout timeout = new Timeout(1000);

//使用自定义Rule,

@Rule

public MethodNameRule methodNameRule = new MethodNameRule();

……

再次运行测试用例,执行结果如下:

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: