单元测试系列之六:JUnit5 技术前瞻
JUnit 5是下一代JUnit。 目标是为JVM上的开发人员端测试创建一个最新的基础。 这包括专注于Java 8及更高版本,以及启用许多不同风格的测试。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
与以前的JUnit版本不同,JUnit 5由三个不同的子项目组成
支持的Java版本
JUnit 5在运行时需要Java 8。 但是,仍然可以测试使用以前版本的JDK编译的代码。
JUnit平台作为在JVM上启动测试框架的基础。 它还定义了用于开发在平台上运行的测试框架的TestEngine API。 此外,该平台提供了一个控制台启动器,从命令行启动平台,为Gradle和Maven构建插件以及基于JUnit 4的Runner,用于在平台上运行任何TestEngine。
JUnit Jupiter是用于在JUnit 5中编写测试和扩展的新编程模型和扩展模型的组合.Jupiter子项目提供了一个用于在平台上运行基于Jupiter的测试的TestEngine。
JUnit Vintage提供了一个用于在平台上运行JUnit 3和JUnit 4的测试的TestEngine。
JUnit 5团队于2017年4月1日发布了里程碑4,目前正在开发额外的里程碑,最终发布GA版本(详见路线图Roadmap)。
JUnit Jupiter带有许多JUnit 4的断言方法,并添加了一些可以与Java 8 lambdas一起使用的方法。
所有JUnit Jupiter断言是org.junit.jupiter.Assertions类中的静态方法.
新特性是分组断言,这在以前Junit4是不被允许的。
以下是断言的Demo:
import static java.time.Duration.ofMillis; import static java.time.Duration.ofMinutes; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTimeout; import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; class AssertionsDemo { @Test void standardAssertions() { assertEquals(2, 2); assertEquals(4, 4, "The optional assertion message is now the last parameter."); assertTrue(2 == 2, () -> "Assertion messages can be lazily evaluated -- " + "to avoid constructing complex messages unnecessarily."); } @Test void groupedAssertions() { //分组断言:在一个分组断言中,所有断言都会被执行,并且任何失败的断言也会一起被报告 assertAll("address", () -> assertEquals("John", address.getFirstName()), () -> assertEquals("User", address.getLastName()) ); } @Test void exceptionTesting() { Throwable exception = assertThrows(IllegalArgumentException.class, () -> { throw new IllegalArgumentException("a message"); }); assertEquals("a message", exception.getMessage()); } @Test void timeoutNotExceeded() { // 下面的断言成功 assertTimeout(ofMinutes(2), () -> { // 执行任务只需不到2分钟 }); } @Test void timeoutNotExceededWithResult() { // 以下断言成功,并返回所提供的对象 String actualResult = assertTimeout(ofMinutes(2), () -> { return "a result"; }); assertEquals("a result", actualResult); } @Test void timeoutNotExceededWithMethod() { // 以下断言调用方法参照并返回一个对象 String actualGreeting = assertTimeout(ofMinutes(2), AssertionsDemo::greeting); assertEquals("hello world!", actualGreeting); } @Test void timeoutExceeded() { // 下面的断言失败,类似的错误信息: // execution exceeded timeout of 10 ms by 91 ms assertTimeout(ofMillis(10), () -> { // 模拟的任务,需要超过10毫秒 Thread.sleep(100); }); } @Test void timeoutExceededWithPreemptiveTermination() { // 下面的断言失败,类似的错误信息: // execution timed out after 10 ms assertTimeoutPreemptively(ofMillis(10), () -> { // 模拟的任务,需要超过10毫秒 Thread.sleep(100); }); } private static String greeting() { return "hello world!"; } }
即使由JUnit Jupiter提供的断言设施对于许多测试场景也是足够的,但有时候需要或需要更多的功率和附加功能,如匹配器。
在这种情况下,JUnit团队建议使用第三方断言库,如AssertJ,Hamcrest,Truth等。因此,开发人员可以自由使用他们选择的断言库。
例如,匹配器和流畅的API的组合可用于使断言更具描述性和可读性。 但是,JUnit Jupiter的org.junit.jupiter.Assertions类不提供像JUnit 4的org.junit.Assert类中的assertThat()方法,它接受Hamcrest Matcher。 相反,鼓励开发人员使用第三方断言库提供的匹配器的内置支持。
以下示例演示了如何在JUnit Jupiter测试中使用Hamcrest的assertThat()支持。 只要将Hamcrest库添加到类路径中,您可以静态导入assertThat(),is()和equalsTo()等方法,然后在下面的assertWithHamcrestMatcher()方法中使用它们。
Demo:
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.jupiter.api.Test; class HamcrestAssertionDemo { @Test void assertWithHamcrestMatcher() { assertThat(2 + 1, is(equalTo(3))); } }
附录:参考
作者原创技术文章,转载请注明出处