JUnit assertThrows 中的可执行文件会发生什么?

What happens with the Executable in a JUnit assertThrows?

我知道 Junit5 Assertions.assertThrows 接受可执行类型的对象。因此,对于构造函数可能不会将空字符串作为名称参数的简单示例:

public Company(String aName, Calendar aFoundingDate)
{
    if (aName == null || aName.length() == 0 || aName.length() > 50) {
        throw new IllegalArgumentException("Invalid name");
    }
    this.name = aName;
    foundingDate = aFoundingDate;
}

我可以这样写一个测试:

// Company constructor test
@Test
void testCompanyConstructor() {
    // Given
    String emptyName = "aabbe";
    Calendar validFoundingDate = Calendar.getInstance();
    validFoundingDate.set(2000, 1, 1);

    // Then
    assertThrows(IllegalArgumentException.class, () -> new Company(emptyName, validFoundingDate));
}

我想知道的是,可执行文件(即 Lambda 表达式)发生了什么? JUnit 是否在 Lambda 表达式上调用 execute() 并在这样做时创建具有空名称的匿名公司对象,异常是

附录: 这些版本是等效的:

// Company constructor test
@Test
void testCompanyConstructor() {
    // Given
    String emptyName = "";
    Calendar validFoundingDate = Calendar.getInstance();
    validFoundingDate.set(2000, 1, 1);

    // Then
    Executable executable = new Executable() {
        public void execute() {
            new Company(emptyName, validFoundingDate);
        }
    };
    assertThrows(IllegalArgumentException.class, executable);
    assertThrows(IllegalArgumentException.class, () -> new Company(emptyName, validFoundingDate));
}

是的,这正是发生的事情。 JUnit 在一个 try { ... } catch (Throwable t) {...} 块。如果捕获到的异常是指定的类型,那么一切都很好。如果不是,那么它会抛出一个 AssertionError。

查看assertThrows的代码可以看出,在AssertThrows::assertThrows的深处有这样的代码:

try {
    executable.execute();
}
catch (Throwable actualException)
    if (expectedType.isInstance(actualException)) {
        return (T) actualException;
    }
    else {
        BlacklistedExceptions.rethrowIfBlacklisted(actualException);
        String message = buildPrefix(nullSafeGet(messageOrSupplier))
                + format(expectedType, actualException.getClass(), "Unexpected exception type thrown");
        throw new AssertionFailedError(message, actualException);
    }
}

所以它基本上调用 Executable 并捕获可能抛出的 Throwable 和 returns 它。如果没有抛出异常或异常类型与预期不同 - 断言失败。