Junit 5官方文档中文版
  • Introduction
  • 用户指南
    • 概况
      • Junit5是什么?
      • 支持的Java版本
      • 获取帮助
    • 安装
      • 依赖元数据
      • 依赖关系图
      • JUnit Jupiter示例项目
    • 编写测试
      • 注解
      • 标准测试类
      • 显示名称
      • 断言
      • 假设
      • 禁用
      • 标签和过滤
      • 测试实例生命周期
      • 嵌套测试
      • 构造函数和方法的依赖注入
      • 测试接口和默认方法
      • 重复测试
      • 参数化测试
      • 测试模板
      • 动态测试
    • 运行测试
      • IDE支持
      • 构建支持
      • 控制台启动器
      • 使用Junit4运行JUnit Platfrom
      • 配置参数
    • 扩展模型
      • 概述
      • 注册扩展
      • 有条件的测试执行
      • 测试实例后处理
      • 测试生命周期回调
      • 异常处理
      • 为测试模板提供调用上下文
      • 在扩展中维持状态
      • 在扩展中支持的实用程序
      • 用户代码和扩展的相对执行顺序
    • 从Junit4迁移
      • 在Junit Platform上运行JUnit4测试
      • 迁移Tips
      • 受限的JUnit4规则支持
    • 高级主题
      • JUnit Platform Launcher API
    • API演进
      • API版本和状态
      • 实验性API
      • @API工具支持
Powered by GitBook
On this page
  1. 用户指南
  2. 编写测试

测试接口和默认方法

Previous构造函数和方法的依赖注入Next重复测试

Last updated 6 years ago

JUnit Jupiter允许在接口default方法中声明@Test,@RepeatedTest,@ParameterizedTest,@ TestFactory,@TestTemplate,@BeforeEach和@AfterEach。如果测试接口或测试类用@TestInstance(Lifecycle.PER_CLASS)注解(请参阅),则可以在测试接口中的static方法或接口default方法上声明@BeforeAll和@AfterAll。这里有些例子。

@TestInstance(Lifecycle.PER_CLASS)
interface TestLifecycleLogger {

    static final Logger LOG = Logger.getLogger(TestLifecycleLogger.class.getName());

    @BeforeAll
    default void beforeAllTests() {
        LOG.info("Before all tests");
    }

    @AfterAll
    default void afterAllTests() {
        LOG.info("After all tests");
    }

    @BeforeEach
    default void beforeEachTest(TestInfo testInfo) {
        LOG.info(() -> String.format("About to execute [%s]",
            testInfo.getDisplayName()));
    }

    @AfterEach
    default void afterEachTest(TestInfo testInfo) {
        LOG.info(() -> String.format("Finished executing [%s]",
            testInfo.getDisplayName()));
    }

}
interface TestInterfaceDynamicTestsDemo {

    @TestFactory
    default Collection<DynamicTest> dynamicTestsFromCollection() {
        return Arrays.asList(
            dynamicTest("1st dynamic test in test interface", () -> assertTrue(true)),
            dynamicTest("2nd dynamic test in test interface", () -> assertEquals(4, 2 * 2))
        );
    }

}
@Tag("timed")
@ExtendWith(TimingExtension.class)
interface TimeExecutionLogger {
}

在你的测试类中,你可以实现这些测试接口来应用它们。

class TestInterfaceDemo implements TestLifecycleLogger,
        TimeExecutionLogger, TestInterfaceDynamicTestsDemo {

    @Test
    void isEqualValue() {
        assertEquals(1, 1, "is always equal");
    }

}

运行TestInterfaceDemo,输出类似以下内容:

:junitPlatformTest
INFO  example.TestLifecycleLogger - Before all tests
INFO  example.TestLifecycleLogger - About to execute [dynamicTestsFromCollection()]
INFO  example.TimingExtension - Method [dynamicTestsFromCollection] took 13 ms.
INFO  example.TestLifecycleLogger - Finished executing [dynamicTestsFromCollection()]
INFO  example.TestLifecycleLogger - About to execute [isEqualValue()]
INFO  example.TimingExtension - Method [isEqualValue] took 1 ms.
INFO  example.TestLifecycleLogger - Finished executing [isEqualValue()]
INFO  example.TestLifecycleLogger - After all tests

Test run finished after 190 ms
[         3 containers found      ]
[         0 containers skipped    ]
[         3 containers started    ]
[         0 containers aborted    ]
[         3 containers successful ]
[         0 containers failed     ]
[         3 tests found           ]
[         0 tests skipped         ]
[         3 tests started         ]
[         0 tests aborted         ]
[         3 tests successful      ]
[         0 tests failed          ]

BUILD SUCCESSFUL

这个特性的另一个可以应用的地方是为接口契约编写测试。例如,您可以编写测试,验证Object.equals或Comparable.compareTo的实现应该如何如下表现。

public interface Testable<T> {

    T createValue();

}
public interface EqualsContract<T> extends Testable<T> {

    T createNotEqualValue();

    @Test
    default void valueEqualsItself() {
        T value = createValue();
        assertEquals(value, value);
    }

    @Test
    default void valueDoesNotEqualNull() {
        T value = createValue();
        assertFalse(value.equals(null));
    }

    @Test
    default void valueDoesNotEqualDifferentValue() {
        T value = createValue();
        T differentValue = createNotEqualValue();
        assertNotEquals(value, differentValue);
        assertNotEquals(differentValue, value);
    }

}
public interface ComparableContract<T extends Comparable<T>> extends Testable<T> {

    T createSmallerValue();

    @Test
    default void returnsZeroWhenComparedToItself() {
        T value = createValue();
        assertEquals(0, value.compareTo(value));
    }

    @Test
    default void returnsPositiveNumberComparedToSmallerValue() {
        T value = createValue();
        T smallerValue = createSmallerValue();
        assertTrue(value.compareTo(smallerValue) > 0);
    }

    @Test
    default void returnsNegativeNumberComparedToSmallerValue() {
        T value = createValue();
        T smallerValue = createSmallerValue();
        assertTrue(smallerValue.compareTo(value) < 0);
    }

}

在你的测试类中,你可以实现两个契约接口,从而继承相应的测试。当然你必须实现抽象方法。

class StringTests implements ComparableContract<String>, EqualsContract<String> {

    @Override
    public String createValue() {
        return "foo";
    }

    @Override
    public String createSmallerValue() {
        return "bar"; // 'b' < 'f' in "foo"
    }

    @Override
    public String createNotEqualValue() {
        return "baz";
    }

}

上述测试仅仅是作为例子,因此不完整。

可以在测试接口上声明@ExtendWith和@Tag,以便实现该接口的类自动继承其注解和扩展。请参阅来获取的源代码。

测试实例生命周期
测试执行前后的回调
TimingExtension