junit5 入门系列教程-13-junit5 测试接口及默认方法

时间:2025-03-27 09:20:14

目录

  • 目录
  • 测试接口和默认方法
    • 定义接口
    • 测试案例
  • 接口契约
    • 接口定义
    • 测试类
  • 系列导航

测试接口和默认方法

JUnit Jupiter允许在接口默认方法上声明@Test、@RepeatedTest、@ParameterizedTest、@TestFactory、@TestTemplate、@BeforeEach和@AfterEach。
如果测试接口或测试类被@TestInstance(Lifecycle.PER_CLASS)注释,
则@BeforeAll和@AfterAll可以在测试接口中的静态方法上声明,也可以在接口默认方法上声明。

这里有一些例子。

定义接口

import ;
import ;
import ;
import ;
import ;
import ;

import ;

@TestInstance(.PER_CLASS)
public interface TestLifecycleLogger {

    static final Logger LOG = (());

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

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

    @BeforeEach
    default void beforeEachTest(TestInfo testInfo) {
        (() -> ("About to execute [%s]",
                ()));
    }

    @AfterEach
    default void afterEachTest(TestInfo testInfo) {
        (() -> ("Finished executing [%s]",
                ()));
    }
}
import ;
import ;

import ;
import ;

import static ;
import static ;
import static ;

public interface TestInterfaceDynamicTestsDemo {

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

可以在测试接口上声明 @ExtendWith@Tag,以便实现该接口的类自动继承其标记和扩展。
查看测试执行前后对 TimingExtension 源代码的回调。

@Tag("timed")
@ExtendWith()
interface TimeExecutionLogger {
}
import ;
import ;

import ;
import ;
import ;
import ;
import ;

public class TimingExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback {

    private static final Logger logger = (());

    private static final String START_TIME = "start time";

    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception {
        getStore(context).put(START_TIME, ());
    }

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        Method testMethod = ();
        long startTime = getStore(context).remove(START_TIME, long.class);
        long duration = () - startTime;

        (() -> ("Method [%s] took %s ms.", (), duration));
    }

    private Store getStore(ExtensionContext context) {
        return ((getClass(), ()));
    }
}

测试案例

import ;

import static ;

class TestInterfaceDemo implements TestLifecycleLogger,
        TimeExecutionLogger, TestInterfaceDynamicTestsDemo {

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

日志如下:

Jun 25, 2018 6:18:43 PM com.github.houbb.jdk.junit5.interfaces.TestLifecycleLogger beforeAllTests
信息: Before all tests
Jun 25, 2018 6:18:43 PM com.github.houbb.jdk.junit5.interfaces.TestLifecycleLogger beforeEachTest
信息: About to execute [isEqualValue()]
Jun 25, 2018 6:18:43 PM com.github.houbb.jdk.junit5.interfaces.TimingExtension afterTestExecution
信息: Method [isEqualValue] took 4 ms.
Jun 25, 2018 6:18:43 PM com.github.houbb.jdk.junit5.interfaces.TestLifecycleLogger afterEachTest
信息: Finished executing [isEqualValue()]
Jun 25, 2018 6:18:43 PM com.github.houbb.jdk.junit5.interfaces.TestLifecycleLogger afterAllTests
信息: After all tests

接口契约

这个特性的另一个可能的应用是为接口契约编写测试。

例如,您可以为对象的实现方式编写测试。 的或 的。

接口定义

public interface Testable<T> {

    T createValue();

}
import ;

import static ;
import static ;
import static ;

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((null));
    }

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

import static ;
import static ;

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

    T createSmallerValue();

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

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

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

测试类

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

public class StringTest
        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";
    }
}

系列导航

系列导航