1. interface TestInterfaceDynamicTestsDemo {
    2. @TestFactory
    3. default Stream<DynamicTest> dynamicTestsForPalindromes() {
    4. return Stream.of("racecar", "radar", "mom", "dad")
    5. .map(text -> dynamicTest(text, () -> assertTrue(isPalindrome(text))));
    6. }
    7. }

    @ExtendWith and @Tag can be declared on a test interface so that classes that implement the interface automatically inherit its tags and extensions. See for the source code of the TimingExtension.

    1. @Tag("timed")
    2. @ExtendWith(TimingExtension.class)
    3. interface TimeExecutionLogger {
    4. }

    Running the TestInterfaceDemo results in output similar to the following:

    1. INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()]
    2. INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms.
    3. INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()]
    4. INFO example.TestLifecycleLogger - About to execute [isEqualValue()]
    5. INFO example.TimingExtension - Method [isEqualValue] took 1 ms.
    6. INFO example.TestLifecycleLogger - Finished executing [isEqualValue()]
    7. INFO example.TestLifecycleLogger - After all tests
    1. public interface Testable<T> {
    2. T createValue();
    3. }
    1. public interface ComparableContract<T extends Comparable<T>> extends Testable<T> {
    2. T createSmallerValue();
    3. @Test
    4. default void returnsZeroWhenComparedToItself() {
    5. T value = createValue();
    6. assertEquals(0, value.compareTo(value));
    7. }
    8. @Test
    9. default void returnsPositiveNumberWhenComparedToSmallerValue() {
    10. T value = createValue();
    11. T smallerValue = createSmallerValue();
    12. }
    13. @Test
    14. default void returnsNegativeNumberWhenComparedToLargerValue() {
    15. T smallerValue = createSmallerValue();
    16. assertTrue(smallerValue.compareTo(value) < 0);
    17. }
    18. }

    In your test class you can then implement both contract interfaces thereby inheriting the corresponding tests. Of course you’ll have to implement the abstract methods.

    1. class StringTests implements ComparableContract<String>, EqualsContract<String> {
    2. @Override
    3. public String createValue() {
    4. return "banana";
    5. }
    6. @Override
    7. public String createSmallerValue() {
    8. return "apple"; // 'a' < 'b' in "banana"
    9. }
    10. @Override
    11. public String createNotEqualValue() {
    12. return "cherry";
    13. }