为了账号安全,请及时绑定邮箱和手机立即绑定

Junit的新长征-Junit5

标签:
Java 测试

这几天做新课时,忽然发现Junit在Junit4这个版本上停留了十几年之后,原来已经出到5了(后知后觉),花了些时间研究了下,发现还真是不简单,我们一起来看看JUnit5上出现了哪些让人激动的新变化


1. 架构

不像之前的Junit版本所有的组件都包含在Junit这一个包中,新的Junit5准确的说包含三个包:

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit platform ,从名字也可以看出来,Junit已不仅仅想简单作为一个测试框架,更多是希望能作为一个测试平台,也就是说通过JUnit platform,其他的自动化测试引擎或自己定制的引擎都可以接入这个平台实现对接和执行。试想下TestNG运行在Junit上,是不是有点意思了? 
JUnit Jupiter, 则是Junit5的核心,它包含了很多丰富的新特性来使JUnit自动化测试更加方便、功能更加丰富和强大。 
JUnit Vintage 则是一个对JUnit3,JUnit4兼容的测试引擎,使旧版本junit的自动化测试脚本可以顺畅运行在junit5下,其实也可以看作是基于junit platform实现的接入范例。

组件的依赖关系如下: 
dependance

2. JDK

JUnit5需要JDK8或以上版本才能支持。


3. 断言

除了之前版本的各种常规断言,新版本还支持AssertThrow和AssertAll两种新的断言

assertAll可以将一组断言集合起来,并一起在报告中体现

    @Test
    void groupedAssertions() {
        // In a grouped assertion all assertions are executed, and any
        // failures will be reported together.
        assertAll("person",
            () -> assertEquals("John", person.getFirstName()),
            () -> assertEquals("Doe", person.getLastName())
        );
    }

assertThrow则是新增的用来专门进行异常预期的断言

    @Test
    void exceptionTesting() {
        Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException("a message");
        });
        assertEquals("a message", exception.getMessage());
    }


4. Tag的支持

新版本提供了tag特性,类似RobotFramework的tag一样可以给测试打标签。便于在测试执行时根据tag来选择执行。

    @Tag("fast")
    @Tag("model")
    class TaggingDemo {

      @Test
      @Tag("taxes")
      void testingTaxCalculation() {
      }
    }


5. 嵌套测试

JUnit5中增加了一种Nested注解,支持在测试中进行嵌套,使测试的层级处理更加丰富

        @Nested
        @DisplayName("after pushing an element")
        class AfterPushing {

            String anElement = "an element";

            @BeforeEach
            void pushAnElement() {
                stack.push(anElement);
            }

            @Test
            @DisplayName("it is no longer empty")
            void isNotEmpty() {
                assertFalse(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when popped and is empty")
            void returnElementWhenPopped() {
                assertEquals(anElement, stack.pop());
                assertTrue(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when peeked but remains not empty")
            void returnElementWhenPeeked() {
                assertEquals(anElement, stack.peek());
                assertFalse(stack.isEmpty());
            }
        }


6. 测试用例参数化

Junit5中支持给测试方法提供参数,提高了测试数据管理的便利性。内建的几种数据源

@ValueSource

     @ParameterizedTest
     @ValueSource(ints = { 1, 2, 3 })
     void testWithValueSource(int argument) {
        assertTrue(argument > 0 && argument < 4);
     }

@EnumSource

     @ParameterizedTest
     @EnumSource(TimeUnit.class)
     void testWithEnumSource(TimeUnit timeUnit) {
        assertNotNull(timeUnit);
     }

还可以提供数据的例外处理,正则匹配等

     @ParameterizedTest
     @EnumSource(value = TimeUnit.class, mode = EXCLUDE, names = { "DAYS", "HOURS" })
     void testWithEnumSourceExclude(TimeUnit timeUnit) {
        assertFalse(EnumSet.of(TimeUnit.DAYS, TimeUnit.HOURS).contains(timeUnit));
        assertTrue(timeUnit.name().length() > 5);
     }

or

     @ParameterizedTest
     @EnumSource(value = TimeUnit.class, mode = MATCH_ALL, names = "^(M|N).+SECONDS$")
     void testWithEnumSourceRegex(TimeUnit timeUnit) {
        String name = timeUnit.name();
        assertTrue(name.startsWith("M") || name.startsWith("N"));
        assertTrue(name.endsWith("SECONDS"));
     }

@MethodSource

     @ParameterizedTest
     @MethodSource("stringProvider")
     void testWithSimpleMethodSource(String argument) {
        assertNotNull(argument);
     }

     static Stream<String> stringProvider() {
        return Stream.of("foo", "bar");
     }

@CsvSource

     @ParameterizedTest
     @CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
     void testWithCsvSource(String first, int second) {
          assertNotNull(first);
          assertNotEquals(0, second);
     }

@CsvFileSource

     @ParameterizedTest
     @CsvFileSource(resources = "/two-column.csv", numLinesToSkip = 1)
     void testWithCsvFileSource(String first, int second) {
          assertNotNull(first);
          assertNotEquals(0, second);
     }

two-column.csv

Country, reference
Sweden, 1
Poland, 2
"United States of America", 3


7. 扩展回调机制

Junit5中对不同测试执行阶段提供了对应的回调接口,使扩展JUnit更加方便

回调方法描述
BeforeAllCallback在@BeforeAll 注解的方法之前执行
AfterAllCallback在@AfterAll 注解的方法之后执行
BeforeEachCallback在@BeforeEach 注解的方法之前执行
AfterEachCallback在@AfterEach 注解的方法之后执行
BeforeTestExecutionCallback在测试方法运行之前执行
AfterTestExecutionCallback在测试方法运行之后执行


8. 动态测试

JUnit Jupiter还引入了一种全新的测试编程模型。 
这种新类型的测试是一种动态测试,它是由一个工厂方法在运行时生成的,该方法用@TestFactory注释。与@Test方法相反,@TestFactory方法本身不是测试用例,而是测试用例的工厂。因此,动态测试是工厂的产品.

@TestFactory
    Iterator<DynamicTest> dynamicTestsFromIterator() {
        return Arrays.asList(
            dynamicTest("5th dynamic test", () -> assertTrue(true)),
            dynamicTest("6th dynamic test", () -> assertEquals(4, 2 * 2))
        ).iterator();
    }


9. Lambda语法支持

JUnit5全面支持JDK8 lambda语法表达。这个本人使用不多,无感

@TestFactory
    Iterator<DynamicTest> dynamicTestsFromIterator() {
        return Arrays.asList(
            dynamicTest("5th dynamic test", () -> assertTrue(true)),
            dynamicTest("6th dynamic test", () -> assertEquals(4, 2 * 2))
        ).iterator();
    }


10. 注解的更新

和JUnit4相比,Junit对注解的使用进行了进一步的优化,以下是一个对照表

FEATUREJUNIT 4JUNIT 5
Declare a test method@Test@Test
Execute before all test methods in the current class@BeforeClass@BeforeAll
Execute after all test methods in the current class@AfterClass@AfterAll
Execute before each test method@Before@BeforeEach
Execute after each test method@After@AfterEach
Disable a test method / class@Ignore@Disabled
Test factory for dynamic testsNA@TestFactory
Nested testsNA@Nested
Tagging and filtering@Category@Tag

总结

Junit5提供了很多新特性,而且更加容易扩展。大家不妨可以尝试。但官方也说明其中尚有较多试验性的功能,如果大规模使用,建议大家不妨再观望一段时间,等确实稳定下来再切换也许更合适

欢迎关注课程《Android自动化测试实战 Java篇》


点击查看更多内容
10人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消