JUnit的新征-JUnit5特性

Junit5

这几天偶然发现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对注解的使用进行了进一步的优化,以下是一个对照表

FEATURE JUNIT 4 JUNIT 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 tests NA @TestFactory
Nested tests NA @Nested
Tagging and filtering @Category @Tag

总结

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 著名的Java单元测试框架Junit 4已经出来很长时间了,当时我发现JUnit 5已经处于测试版,就准备写文章来...
    乐百川阅读 8,221评论 0 17
  • 起源 前事不忘,后事之师。--《战国策·赵策一》 对Java程序员而言,JUnit无疑是使用最广泛的单元测试框架。...
    麦壳阅读 873评论 0 4
  • JUnit是一个编写测试代码的框架,它是单元测试框架的xUnit体系结构中的一个,目前主要使用的是JUnit 4 ...
    wangdy12阅读 1,142评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • JUnit 5简介 与之前的版本不同,JUnit 5 由三个不同的模块组成。第一个模块是 JUnit 平台,其主要...
    周润发_223a阅读 2,077评论 0 4