assertAll 与 JUnit5 中的多个断言
assertAll vs multiple assertions in JUnit5
是否有任何理由将多个断言分组:
public void shouldTellIfPrime(){
Assertions.assertAll(
() -> assertTrue(isPrime(2)),
() -> assertFalse(isPrime(4))
);
}
而不是这样做:
public void shouldTellIfPrime(){
Assertions.assertTrue(isPrime(2));
Assertions.assertFalse(isPrime(4));
}
根据文档here
Asserts that all supplied executables do not throw an AssertionError.
If any supplied Executable throws an AssertionError, all remaining
executables will still be executed, and all failures will be
aggregated and reported in a MultipleFailuresError. However, if an
executable throws an exception that is not an AssertionError,
execution will halt immediately, and the exception will be rethrown as
is but masked as an unchecked exception.
所以主要区别在于 assertAll 将允许所有断言在不中断流程的情况下执行,而其他像 assertTrue 和lot 将停止带有 AssertionError
的测试
因此,在您的第一个示例中,无论是否通过失败,两个断言都会执行,而在第二个示例中,如果第一个断言失败,测试将停止。
Is there any reason to group multiple assertions
如果您希望在单元测试中执行所有断言。
assertAll
的有趣之处在于它 always checks all of the assertions that are passed to it,无论失败多少次。如果全部通过,则一切都很好 - 如果至少有一个失败,您将获得所有错误的详细结果(并且就此而言是正确的)。
它最适合用于断言一组在概念上属于一起的属性。你的第一直觉应该是 "I want to assert this as one".
例子
您的具体示例不是 assertAll
的最佳用例,因为使用质数和非质数检查 isPrime
是相互独立的 - 以至于我建议写两个测试方法。
但假设您有一个简单的 class,例如包含字段 city
、street
、number
的地址,并且想断言这些正是您所期望的成为:
Address address = unitUnderTest.methodUnderTest();
assertEquals("Redwood Shores", address.getCity());
assertEquals("Oracle Parkway", address.getStreet());
assertEquals("500", address.getNumber());
现在,一旦第一个断言失败,您将永远看不到第二个断言的结果,这会很烦人。有很多解决方法,JUnit Jupiter 的 assertAll
就是其中之一:
Address address = unitUnderTest.methodUnderTest();
assertAll("Should return address of Oracle's headquarter",
() -> assertEquals("Redwood Shores", address.getCity()),
() -> assertEquals("Oracle Parkway", address.getStreet()),
() -> assertEquals("500", address.getNumber())
);
如果被测方法returns地址错误,这是你得到的错误:
org.opentest4j.MultipleFailuresError:
Should return address of Oracle's headquarter (3 failures)
expected: <Redwood Shores> but was: <Walldorf>
expected: <Oracle Parkway> but was: <Dietmar-Hopp-Allee>
expected: <500> but was: <16>
是否有任何理由将多个断言分组:
public void shouldTellIfPrime(){
Assertions.assertAll(
() -> assertTrue(isPrime(2)),
() -> assertFalse(isPrime(4))
);
}
而不是这样做:
public void shouldTellIfPrime(){
Assertions.assertTrue(isPrime(2));
Assertions.assertFalse(isPrime(4));
}
根据文档here
Asserts that all supplied executables do not throw an AssertionError.
If any supplied Executable throws an AssertionError, all remaining executables will still be executed, and all failures will be aggregated and reported in a MultipleFailuresError. However, if an executable throws an exception that is not an AssertionError, execution will halt immediately, and the exception will be rethrown as is but masked as an unchecked exception.
所以主要区别在于 assertAll 将允许所有断言在不中断流程的情况下执行,而其他像 assertTrue 和lot 将停止带有 AssertionError
的测试因此,在您的第一个示例中,无论是否通过失败,两个断言都会执行,而在第二个示例中,如果第一个断言失败,测试将停止。
Is there any reason to group multiple assertions
如果您希望在单元测试中执行所有断言。
assertAll
的有趣之处在于它 always checks all of the assertions that are passed to it,无论失败多少次。如果全部通过,则一切都很好 - 如果至少有一个失败,您将获得所有错误的详细结果(并且就此而言是正确的)。
它最适合用于断言一组在概念上属于一起的属性。你的第一直觉应该是 "I want to assert this as one".
例子
您的具体示例不是 assertAll
的最佳用例,因为使用质数和非质数检查 isPrime
是相互独立的 - 以至于我建议写两个测试方法。
但假设您有一个简单的 class,例如包含字段 city
、street
、number
的地址,并且想断言这些正是您所期望的成为:
Address address = unitUnderTest.methodUnderTest();
assertEquals("Redwood Shores", address.getCity());
assertEquals("Oracle Parkway", address.getStreet());
assertEquals("500", address.getNumber());
现在,一旦第一个断言失败,您将永远看不到第二个断言的结果,这会很烦人。有很多解决方法,JUnit Jupiter 的 assertAll
就是其中之一:
Address address = unitUnderTest.methodUnderTest();
assertAll("Should return address of Oracle's headquarter",
() -> assertEquals("Redwood Shores", address.getCity()),
() -> assertEquals("Oracle Parkway", address.getStreet()),
() -> assertEquals("500", address.getNumber())
);
如果被测方法returns地址错误,这是你得到的错误:
org.opentest4j.MultipleFailuresError:
Should return address of Oracle's headquarter (3 failures)
expected: <Redwood Shores> but was: <Walldorf>
expected: <Oracle Parkway> but was: <Dietmar-Hopp-Allee>
expected: <500> but was: <16>