Junit5系列-Junit5中Assertions断言类

目录

    • 系列导航
    • 简介
    • 案例解析
    • 源码解析
    • Assertions与AssertNull

系列导航

点击跳转到系列博文目录导航

简介

junit5中的JUnit Jupiter提供了Assertions类来替代了junit4中的Assert类并且添加了一些新的方法,所以工作过程中完全可以使用Assertions代替Assert类。
其包名称为:org.junit.jupiter.api.Assertions
Assertions中提供的方法都是静态方法,我们可以通过import静态资源进行使用,例如:

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

当然上述是导入了所有的方法,单独导入也可。

案例解析

下面对Assertions进行一个简单的应用
代码的注释都很清楚,就不再多说了

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static java.time.Duration.ofMillis;
import static java.time.Duration.ofMinutes;
import static org.junit.jupiter.api.Assertions.*;
/**
 * @author liyangyang
 * @date 2019/1/8
 */
class AssertionsDemo {
    //定义一个person对象,Person类里面有两个参数lastName,firstName
    static Person person = new Person();

    /**
     * 使用 @BeforeAll注解在所有测试方法执行前执行person对象的赋值
     */
    @BeforeAll
    static void initPerson(){
        person.setFirstName("John");
        person.setLastName("Doe");
    }

    /**
     * assertEquals比较两个值是否相同
     * assertTrue 判断括号里面的参数是否为true
     */
    @Test
    void standardAssertions() {
        assertEquals(2, 2);
        //当不相等时,会打印出第三个参数,下面的所有的此类型的参数都是这种作用
        assertEquals(4, 5, "The optional assertion message is now the last parameter.");
        assertTrue('a' < 'b', "Assertion messages can be lazily evaluated -- "
                + "to avoid constructing complex messages unnecessarily.");
    }

    /**
     * assertAll()方法用于将多个测试语句放在一个组中执行
     * 组中若有一个测试语句不通过,则这个组将会一起报错.
     * 方法中第一个参数:组名称
     * 方法中第二个参数:组测试语句
     */
    @Test
    void groupedAssertions() {
        assertAll("person",
                () -> assertEquals("John", person.getFirstName()),
                () -> assertEquals("Doe", person.getLastName())
        );
    }

    /**
     * assertAll()方法也可以嵌套多个assertAll()方法
     * 其中嵌套的多个测试组,这些组只会打印出这个组和父组的错误,对其他的组没有影响
     */
    @Test
    void dependentAssertions() {
        assertAll("properties",
                //第一个测试组
                () -> {
                    String firstName = person.getFirstName();
                    assertNotNull(firstName);

                    assertAll("first name",
                            () -> assertTrue(firstName.startsWith("J")),
                            () -> assertTrue(firstName.endsWith("n"))
                    );
                },
                //第二个测试组
                () -> {
                    String lastName = person.getLastName();
                    assertNotNull(lastName);

                    assertAll("last name",
                            () -> assertTrue(lastName.startsWith("D")),
                            () -> assertTrue(lastName.endsWith("e"))
                    );
                }
        );
    }

    /**
     * assertThrows()可以用来判断lambda表达式中的代码抛出的异常
     * 比如下面案例就是测试了抛出异常的信息是否相同
     * 参数:
     * 1:异常类声明
     * 2:测试代码Lambda表达式
     */
    @Test
    void exceptionTesting() {
        Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
            try {
                //这里只是简单的做个测试,当然1/0不该抛IllegalArgumentException异常 ,只是简单的测试一下
              int s = 1/0;
            }catch (Exception e){
                throw new IllegalArgumentException("a message");
            }
        });
        assertEquals("a message", exception.getMessage());
    }

    /**
     * assertTimeout()对方法执行时间进行测试
     * 这里要借助java.time.Duration中的方法结合实现
     * 实例中执行的代码部分必须在2分钟之内执行完毕,否则测试不通过
     */
    @Test
    void timeoutNotExceeded() {
        assertTimeout(ofMinutes(2), () -> {
            //执行的代码部分
        });
    }

    /**
     * assertTimeout()还可以接受一个返回值(泛型 T)
     * 被测试代码如果通过测试并返回一个值,这个值被assertTimeout()方法返回
     */
    @Test
    void timeoutNotExceededWithResult() {
        String actualResult = assertTimeout(ofMinutes(2), () -> {
            return "a result";
        });
        assertEquals("a result", actualResult);
    }

    /**
     * assertTimeout()毫秒案例
     */
    @Test
    void timeoutExceeded() {
        assertTimeout(ofMillis(10), () -> {
            Thread.sleep(100);
        });
    }
}

这里只是介绍一下其用法,其中还有好多方法没涉及到,者要等我们在使用的过程中再去查找合适的方法。

相信通过上述案例你应该对Assertions有个大体的了解, 下面再细说一下。

源码解析

因为代码太长了,就不贴代码了,大家有需要可以自行查看。
里面有好多静态测试方法,每个方法又有各自的重载。
Junit5系列-Junit5中Assertions断言类_第1张图片
这只是截取了不到三分之一的方法。

下面通过介绍public static void assertNull(Object actual, String message)这个判断对象为空的方法,来大致的看一下其实现过程。

  1. Assertions中的assertNull方法源码
 public static void assertNull(Object actual, String message) {
        AssertNull.assertNull(actual, message);
}

调用了AssertNull类中的assertNull方法

  1. AssertNull类中的assertNull方法源码
static void assertNull(Object actual, String message) {
        if (actual != null) {
            failNotNull(actual, message);
        }

}
  • 判断参数actual是否为null,若为null则表示测试成功,方法结束,不报错。
  • 如果参数actual不为空,则要调用failNotNull方法
  1. failNotNull方法源码
private static void failNotNull(Object actual, String message) {
        AssertionUtils.fail(AssertionUtils.buildPrefix(message) + "expected:  but was: <" + actual + ">", (Object)null, actual);
}

这个方法主要就是组装了错误消息,并将被验证参数传递到下一层

  1. fail方法源码
static void fail(String message, Object expected, Object actual) {
        throw new AssertionFailedError(message, expected, actual);
}

在这里直接抛出了一个自定义异常。
到这里一个测试的过程就几乎结束了,大体来说不难,大家如果还想了解其他的方法源码,可以自己debug跟踪源码来查看。

  1. 最后简单的看一下这个自定义异常AssertionFailedError吧
    其继承关系为:
public class AssertionFailedError extends AssertionError
--->
public class AssertionError extends Error
--->
public class Error extends Throwable

可以看书这是正常的自定义异常的模式,继承JDK自带的java.long.error类,实现自己的Error类,这里的AssertionError是所有Assertions类中方法报错的父类,其他特定的错误类就是继承的此类。

Assertions与AssertNull

另外,在上述过程中我们知道,Assertions.assertNull()其实就是调用的AssertNull中的assertNull()实现的,我们看一下AssertNull的源码:

class AssertNull {
    private AssertNull() {
    }
    //包可见静态方法
    static void assertNull(Object actual) {
        assertNull(actual, (String)null);
    }
    //包可见静态方法
    static void assertNull(Object actual, String message) {
        if (actual != null) {
            failNotNull(actual, message);
        }

    }
    //包可见静态方法
    static void assertNull(Object actual, Supplier<String> messageSupplier) {
        if (actual != null) {
            failNotNull(actual, AssertionUtils.nullSafeGet(messageSupplier));
        }

    }
    //类内调用方法
    private static void failNotNull(Object actual, String message) {
        AssertionUtils.fail(AssertionUtils.buildPrefix(message) + "expected:  but was: <" + actual + ">", (Object)null, actual);
    }
}

再看一下这两个类是不是在一个包中:
Junit5系列-Junit5中Assertions断言类_第2张图片
从源码和图片中不难发现,AssertNull中其实和Assertions一样也是提供了包内可见的静态方法 ,所以我们也可以通过引入import static org.junit.jupiter.api.AssertNull.*;来直接使用AssertNull中的方法,不过这可不是个好想法。

Assertions将测试方法集中在该方法内,不仅便于管理,还减少代码的复杂度,性能没有任何影响,为什么要去直接使用AssertNull等类呢,嘿嘿

最后:当然,Assertions提供的断言方法虽然多,但有时候还是不够的,当Junit5不支持你的单元测试需求时,Junit5官方还是鼓励程序员去使用第三方支持库的,比如:AssertJ、Hamcrest,Truth等。。。。

如果转载此博文,请附上本文链接:https://blog.csdn.net/csdn___lyy ,谢谢合作~

如果感觉这篇文章对您有所帮助,请点击一下“喜欢”或者“关注”博主,您的喜欢和关注将是我前进的最大动力!

refer: 官网

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2gwn5c4zib6s0

你可能感兴趣的:(单元测试,单元测试相关)