JUnit 5 –基础

本文介绍了JUnit 5的基础知识,包括测试生命周期、参数解析、断言(基础、超时、异常)以及如何设置和使用JUnit 5测试。通过示例展示了JUnit 5如何简化Java单元测试。
摘要由CSDN通过智能技术生成

JUnit 5是适用于Java的下一代单元测试框架,具有许多有趣的功能,包括嵌套测试,参数化测试,新的扩展API或Java 8支持。

本文展示了JUnit 5的基本概念,包括测试生命周期,参数注入和断言(基本,超时和异常)。

文献资料

首先,我认为JUnit 5文档很棒。 它不仅包含全面的框架文档,还包含许多示例,包括许多示例。 学习JUnit 5时请不要错过文档: http : //junit.org/junit5/docs/current/user-guide/

依存关系

首先,JUnit 5需要Java 8才能运行。 最后。 这带来了在测试中使用Lambda表达式的可能性,并使它们更加简洁(Lambda表达式主要用于断言中)。 其次,JUnit 5由按JUnit平台,JUnit Jupiter和JUnit Vintage分组的多个工件组成。 这听起来可能很吓人,但是如今使用Maven或Gradle之类的工具根本不是问题,要开始使用,您实际上只需要一个依赖项。 Gradle的基本配置如下所示:

buildscript {
    ext {
        junitPlatformVersion = '1.0.1'
        junitJupiterVersion = '5.0.1'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.junit.platform:junit-platform-gradle-plugin:${junitPlatformVersion}"
    }
}

apply plugin: 'java'
apply plugin: 'org.junit.platform.gradle.plugin'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies { 
    testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
}

task wrapper(type: Wrapper) {
    gradleVersion = '4.1'
}

JUnit 5测试类和方法

在测试类(从org.junit.jupiter.api导入)中使用的常见测试注释是:

  • @BeforeAll –在测试类中的所有方法之前执行
  • @BeforeEach –在测试类中的每个测试方法之前执行
  • @Test –实际测试方法
  • @AfterEach –在测试环境中的每个测试方法之后执行
  • @AfterAll –在测试过程中的所有方法之后执行

其他基本但有用的注释:

  • @DisplayName –测试类或方法的自定义显示名称
  • @Disabled –禁用测试类或方法
  • @RepeatedTest –用测试方法制作测试模板
  • @Tag –标记测试类或方法以进一步选择测试

一个基本的例子:

import org.junit.jupiter.api.*;

@DisplayName("JUnit5 - Test basics")
class JUnit5Basics {

    @BeforeAll
    static void beforeAll() {
        System.out.println("Before all tests (once)");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("Runs before each test");
    }

    @Test
    void standardTest() {
        System.out.println("Test is running");
    }

    @DisplayName("My #2 JUnit5 test")
    @Test
    void testWithCustomDisplayName() {
        System.out.println("Test is running");
    }

    @DisplayName("Tagged JUnit5 test ")
    @Tag("cool")
    @Test
    void tagged() {
        System.out.println("Test is running");
    }

    @Disabled("Failing due to unknown reason")
    @DisplayName("Disabled test")
    @Test
    void disabledTest() {
        System.out.println("Disabled, will not show up");
    }

    @DisplayName("Repeated test")
    @RepeatedTest(value = 2, name = "#{currentRepetition} of {totalRepetitions}")
    void repeatedTestWithRepetitionInfo() {
        System.out.println("Repeated test");
    }

    @AfterEach
    void afterEach() {
        System.out.println("Runs after each test");
    }
}

注意,测试类和方法不必是公共的 ,它们可以是包私有的

测试执行生命周期

在JUnit 5中,默认情况下会为测试类中的每个测试方法创建一个新的测试实例。 可以使用类级别@TestInstance注释来调整此行为:

import org.junit.jupiter.api.*;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DisplayName("JUnit5 - Test lifecycle adjustments")
class JUnit5PerClassLifecycle {

    private Object first = new Object();
    private Object second;

    @BeforeAll
    void beforeAll() {
        this.second = this.first;
        System.out.println("Non static before all.");
    }

    @BeforeEach
    void beforeEach() {
        Assertions.assertEquals(first, second);
    }

    @Test
    void first() {
        Assertions.assertEquals(first, second);
    }

    @Test
    void second() {
        Assertions.assertEquals(first, second);
    }

    @AfterAll
    void afterAll() {
        System.out.println("Non static after all.");
    }

    @AfterEach
    void afterEach() {
        Assertions.assertEquals(first, second);
    }
}

PER_CLASS模式下,将为所有测试创建单个测试实例,并且@BeforeAll@AfterAll方法不再需要是静态的。

参数解析

测试和回调方法现在可以采用org.junit.jupiter.api.TestInfoorg.junit.jupiter.api.RepetitionInfoorg.junit.jupiter.api.TestReporter类的参数。

另外,由于使用了非常简单但功能强大的JUnit 5扩展API,因此在方法中解析自定义参数只需提供自己的org.junit.jupiter.api.extension.ParameterResolver实现即可。

class JUnit5BuiltInParameterResolution {

    @BeforeAll
    static void beforeAll(TestInfo testInfo) {
        System.out.println("Before all can take parameters. Started: " + testInfo.getDisplayName());
    }

    @BeforeAll
    static void beforeAll(TestReporter testReporter) {
        testReporter.publishEntry("myEntry", "myValue");
    }

    @BeforeAll
    static void beforeAll(TestInfo testInfo, TestReporter testReporter) {
        testReporter.publishEntry("myOtherEntry", testInfo.getDisplayName());
    }


    @BeforeEach
    void beforeEach(TestInfo testInfo) {

    }

    @Test
    void standardTest(TestInfo testInfo) {

    }

    @DisplayName("Repeated test")
    @RepeatedTest(value = 2, name = "#{currentRepetition} of {totalRepetitions}")
    void repeatedTest(RepetitionInfo repetitionInfo) {
        System.out.println("Repeated test - " + repetitionInfo.toString());
    }

    @AfterAll
    static void afterAll() {

    }

    @AfterAll
    static void afterAll(TestInfo testInfo) {

    }

    @AfterEach
    void afterEach() {

    }
}

断言

JUnit 5带有许多标准断言,可以在org.junit.jupiter.api.Assertions类中找到。

基本断言

基本主张是: assertEqualsassertArrayEqualsassertSameassertNotSameassertTrueassertFalseassertNullassertNotNullassertLinesMatchassertIterablesMatch

例:

@Test
void basicAssertions() {
    // arrange
    List<String> owners = Lists.newArrayList("Betty Davis", "Eduardo Rodriquez");

    // assert
    assertNotNull(owners);
    assertSame(owners, owners);
    assertFalse(owners::isEmpty); // Lambda expression
    assertEquals(2, owners.size(), "Found owner names size is incorrect");
    assertLinesMatch(newArrayList("Betty Davis", "Eduardo Rodriquez"), owners);
    assertArrayEquals(
        new String[]{"Betty Davis", "Eduardo Rodriquez"}, 
        owners.toArray(new String[0])
    );
}

断言所有

Assertions.assertAll断言所有提供的可执行文件均不会引发异常:

Assertions.assertAll(
    () -> Assertions.assertNotNull(null, "May not be null"),
    () -> Assertions.assertTrue(false, "Must be true")
);

上面将报告多个失败:

org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
    May not be null ==> expected: not <null>
    Must be true

注意:您可能想阅读有关JUnit 4和AssertJ中的替代方法的信息-http: //blog.codeleak.pl/2015/09/assertjs-softassertions-do-we-need-them.html

超时断言

使用超时断言来验证未超过任务的执行时间。 超时断言有两种: assertTimeoutassertTimeoutPreemptively 。 都拿两个

  • 同步执行任务,等待任务完成,然后声明超时:
@Test
void assertTimeout() {
    // arrange
    Executable task = () -> Thread.sleep(1000);

    // waits for the task to finish before failing the test
    Assertions.assertTimeout(Duration.ofMillis(100), task::execute);
}

@Test
void assertTimeoutWithThrowingSupplier() {
    // arrange
    ThrowingSupplier<String> task = () -> "result";

    // waits for the task to finish before failing the test
    Assertions.assertTimeout(Duration.ofMillis(100), task::get);
}
  • 异步执行任务(在新线程中),到超时时中止执行:
@Test
void assertTimeoutPreemptively() {
    // arrange
    Executable task = () -> Thread.sleep(1000);

    // abort execution when timeout exceeded
    Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), task::execute);
}

@Test
void assertTimeoutPreemptivelyWithThrowingSupplier() {
    // arrange
    ThrowingSupplier<String> task = () -> "result";

    // abort execution when timeout exceeded, return the result
    String result = Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), task::get);

    Assertions.assertEquals("result", result);
}

异常断言

JUnit 5内置的assertThrows获取预期的异常类型作为第一个参数,而可执行文件(功能接口)则可能将异常作为第二个参数。 如果未引发任何异常或其他类型的异常,则该方法将失败。 该方法返回异常本身,该异常可用于进一步的声明:

@Test
void assertException() {
    // arrange
    Executable throwingExecutable = () -> {
        throw new RuntimeException("Unexpected error!");
    };

    // act and assert
    RuntimeException thrown = Assertions.assertThrows(
        RuntimeException.class, throwingExecutable::execute, "???"
    );

    Assertions.assertAll(
        () -> Assertions.assertEquals("Unexpected error!", thrown.getMessage()),
        () -> Assertions.assertNotNull(thrown.getCause())
    );
}

注意:您可能想阅读有关JUnit 4中的替代方法的信息-http: //blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html

摘要

JUnit 5具有许多功能。 在本文中,仅演示了基础知识,但这足以让您开始编写第一个JUnit 5测试。

也可以看看

翻译自: https://www.javacodegeeks.com/2017/10/junit-5-basics-2.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值