Junit5系列-Junit5中assertThrows()与assertDoesNotThrow()方法详解

目录

    • 系列导航
    • 简介
    • 案例分析
    • 源码分析

系列导航

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

简介

Junit5中新添加了对方法抛出异常的断言Assertions类中的assertThrows()和assertDoesNotThrow(),使用此方法可以对被测试方法抛出的异常进行断言测试,而在junit4中的对异常进行断言实现相对来说比较麻烦的。

  • assertThrows()主要对被测试方法的抛出异常进行测试,测试所抛出的异常是否满足预期。
  • assertDoesNotThrow()主要用来判定被测试方法是否抛出了异常,如果抛出异常则断言失败,无异常抛出则断言成功。

下面来看一些案例使用:

案例分析

其中每个方法的作用代码中的注释写的已经非常清楚了,就不再赘述了.

大家最好将代码自己测试一遍,可以加深理解与记忆!

案例代码:

1.使用到的被测试方法

public class AssertTestModel {
    public static void testThrowArithmeticException(int numA,int numB){
        try {
            int result = numA/numB;
        }catch (ArithmeticException e){
            throw new ArithmeticException("The numB not allowed to '0'!!");
        }
    }
}

2.测试案例

import cn.yoylee.junit5.AssertTestModel;
import org.junit.jupiter.api.Test;

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

/**
 * @author liyangyang
 * @date 2019/1/14
 */
class AssertThrowsTest {

    @Test
    void testAssertThrows(){
        //2:如果抛出的异常与设定的异常相同,则这一步的断言成功并返回一个异常的顶级父类
        Throwable exception = assertThrows(ArithmeticException.class,()->{
            //1:执行此语句会抛出一个ArithmeticException异常,被assertThrows方法捕获
            AssertTestModel.testThrowArithmeticException(2,0);
        });
        //3:接下来便可以对返回的异常进行一些其他的测试
        //比如对异常的信息进行断言测试等。。
        assertEquals("The numB not allowed to '0'!!",exception.getMessage());
    }

    @Test
    void testAssertDoesNotThrow1(){
        //因为函数式编程中的执行语句抛出了异常,所以断言失败
        assertDoesNotThrow(()->{
            AssertTestModel.testThrowArithmeticException(2,0);
        });
    }

    @Test
    void testAssertDoesNotThrow2(){
        //断言成功
        assertDoesNotThrow(()->{
            AssertTestModel.testThrowArithmeticException(2,1);
        });
    }
    
    @Test
    void testtestAssertDoesSNotThrowHaveReturn(){
        //这是带返回参数的assertDoesNotThrow方法,在没有异常抛出的情况下会返回一个值
        int re =  assertDoesNotThrow(() -> {
            int result = AssertTestModel.testThrowArithmeticException(2,1);
            return result;
        });

        //其实上面的语句可以简化为下面的语句不过为了便于理解,还是使用的上述表达
//        int re =  assertDoesNotThrow(() -> AssertTestModel.testThrowArithmeticException(2,1));

        //可以对返回的结果值进行一些测试等
        assertEquals(re,2);
    }
}

到这里大家应该已经知道如何使用这两个方法了,但是其执行过程是怎样的,怎样设计的呢?我们接下来看一下

源码分析

首先,assertThrows有三个重载方法:

    public static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable) {
        return AssertThrows.assertThrows(expectedType, executable);
    }

    public static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable, String message) {
        return AssertThrows.assertThrows(expectedType, executable, message);
    }

    public static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable, Supplier<String> messageSupplier) {
        return AssertThrows.assertThrows(expectedType, executable, messageSupplier);
    }

我们可以看到,其中都是调用了AssertThrows.assertThrows方法,这里的AssertThrows和Assertions的关系和我们在Junit5系列-Junit5中Assertions断言类一文中Assertions和assertTrue关系一样。
接下来就看一下AssertThrows.assertThrows()到底是何许人也:

private static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable, Object messageOrSupplier) {
        try {
            //执行参数executable中设置的语句
            executable.execute();
        } catch (Throwable var5) {
            //判断捕获的异常是否和自定义的异常类相同,相同则返回异常对象
            if (expectedType.isInstance(var5)) {
                return var5;
            }
            
            //如果捕获的异常和自定义的异常不同,通过自定义的打印信息messageOrSupplier组装异常并抛出(AssertionFailedError为Junit5的自定义异常)
            String message = AssertionUtils.buildPrefix(AssertionUtils.nullSafeGet(messageOrSupplier)) + AssertionUtils.format(expectedType, var5.getClass(), "Unexpected exception type thrown");
            throw new AssertionFailedError(message, var5);
        }
        //如果执行的语句没有异常,组装“没有异常的”异常抛出
        String message = AssertionUtils.buildPrefix(AssertionUtils.nullSafeGet(messageOrSupplier)) + String.format("Expected %s to be thrown, but nothing was thrown.", AssertionUtils.getCanonicalName(expectedType));
        throw new AssertionFailedError(message);
}

我在源码中注释了其运行过程,相对来说是比较简单的,这里的参数参数介绍一下:

  • 返回类型:,继承自Throwable类的子类型,必须是继承Throwable的子类。所以我们在测试方法中可以直接使用Throwable接受返回值。
  • 参数:Class expectedType,定义想要测试的异常类型
  • 参数:Object messageOrSupplier,这里Object类型的原因是可能会接受String类型的自定义信息类型,还有可能接受函数式接口Supplier的自定义信息。
  • 参数:Executable executable,函数式接口,可以使用lambda表达式,可以稍微看一下其源码:
@FunctionalInterface
@API(
    status = Status.STABLE,
    since = "5.0"
)
public interface Executable {
    void execute() throws Throwable;
}

其中@FunctionalInterface可以看出是一个函数式接口,无参无返回值的调用方法。

好了,到这里大家应该对assertThrows方法有个全面的了解,对于的assertDoseNotThrows方法来说,实现方式类似,有6个重载方法,3个有返回值的3个无返回值的重载, 最后都是调用的AssertDoesNotThrow.assertDoesNotThrow()方法实现的,其源码为:

//泛型返回值
private static <T> T assertDoesNotThrow(ThrowingSupplier<T> supplier, Object messageOrSupplier) {
        try {
            //函数式接口方法执行,无异常正常返回
            return supplier.get();
        } catch (Throwable var4) {
            //捕获异常则根据messageOrSupplier自定义消息组装异常并抛出
            String message = AssertionUtils.buildPrefix(AssertionUtils.nullSafeGet(messageOrSupplier)) + "Unexpected exception thrown: " + var4.getClass().getName();
            throw new AssertionFailedError(message, var4);
        }
 }

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

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

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