Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JUnit 5 - The New Testing Framework for Java and Platform for the JVM

JUnit 5 - The New Testing Framework for Java and Platform for the JVM

Over the last decade a lot has happened in the world of Java and testing, but JUnit 4 hasn't kept up. Now JUnit 5 is here to help shape the future of testing on the JVM with a focus on Java 8 language features, extensibility, and a modern programming API for testing in Java. Moreover, JUnit isn't just a Java testing framework anymore. Third parties are already developing test engines for Scala, Groovy, Kotlin, etc. that run on the new JUnit Platform.

In this session, we will start off with an overview of the inspiration for and architecture of JUnit 5, from launchers to test engines. Then, we will take an example-driven tour of the new Jupiter programming model. We will explore the Jupiter extension model, learn about the extension points it provides, and see how custom extensions for conditional tests, method parameter resolution, lifecycle callbacks etc. are authored and registered. To round off the session, we will discuss migration strategies and compatibility with JUnit 4 and look at the roadmap of what's still to come.

Marc Philipp

March 23, 2017
Tweet

More Decks by Marc Philipp

Other Decks in Programming

Transcript

  1. JUnit 5

    View Slide

  2. Marc Philipp
    • Senior Software Engineer @ in Germany
    • JUnit Maintainer since 2012
    • Twitter: @marcphilipp
    • Web: http://www.marcphilipp.de

    View Slide

  3. Programming Model

    View Slide

  4. DEMO

    View Slide

  5. Meta Annotations
    Annotations can be combined to enable re-use:


    @Target(ElementType.METHOD)

    @Retention(RetentionPolicy.RUNTIME)

    @Tag("fast")

    @Test

    public @interface FastTest {}
    Usage:


    @FastTest

    void test() {}

    Equivalent:


    @Tag("fast")

    @Test

    void test() {}

    View Slide

  6. @Nested Tests
    @DisplayName("A stack")
    class TestingAStackDemo {
    @Test
    @DisplayName("is instantiated with new Stack()")
    void isInstantiatedWithNew() {/* ... */}
    @Nested
    @DisplayName("when new")
    class WhenNew {
    @BeforeEach
    void createNewStack() {/* ... */}
    @Test
    @DisplayName("is empty")
    void isEmpty() {/* ... */}
    // ...
    @Nested
    @DisplayName("after pushing an element")
    class AfterPushing {
    @BeforeEach
    void pushAnElement() {/* ... */}
    @Test
    @DisplayName("it is no longer empty")
    void isNotEmpty() {/* ... */}
    // ...
    }
    }
    }

    View Slide

  7. Dynamic Tests
    @TestFactory
    Stream dynamicTestsFromStream() {
    return IntStream.iterate(0, n -> n + 2).limit(100)
    .mapToObj(n -> dynamicTest("test" + n, () -> {
    assertTrue(n % 2 == 0);
    }));
    }

    View Slide

  8. Why do we need a new
    JUnit?

    View Slide

  9. Runner
    • Very powerful: Almost every aspect of test
    execution can be changed
    • But: You can only have one Runner per test class!
    • You can’t combine Runners, e.g.

    SpringJUnit4ClassRunner + Parameterized

    View Slide

  10. Rules
    • Extension mechanism introduced in JUnit 4.7
    • Wraps execution of a test (@Rule) or a test class
    (@ClassRule)
    • Designed to be combined — great for simple use cases
    • But: a single rule cannot be used for method-level and
    class-level callbacks, no support for instance-level callbacks

    View Slide

  11. http://blog.takipi.com/the-top-100-java-libraries-in-2016-after-analyzing-47251-dependencies/

    View Slide

  12. Existing Architecture
    Everyone uses the junit.jar.

    View Slide

  13. Renaming a private field should
    not break anything, right?
    4.11 4.12-beta-1

    View Slide

  14. –Johannes Link, https://jaxenter.com/crowdfunding-for-junit-lambda-is-
    underway-119546.html
    „The success of JUnit as a platform prevents the
    development of JUnit as a tool.“

    View Slide

  15. Modularization

    View Slide

  16. Separation of Concerns
    1. An API to write tests (Jupiter API)
    2. Extensible mechanisms to discover and execute
    tests (Test Engine SPI)
    3. An API for test execution by tools (Launcher API)

    View Slide

  17. P L AT F O R M
    J U P I T E R
    V I N TA G E
    P A R T Y
    T H I R D

    View Slide

  18. P L AT F O R M
    J U P I T E R
    V I N TA G E
    P A R T Y
    T H I R D

    View Slide

  19. JUnitPlatform Runner for a single class
    import org.junit.jupiter.api.Test;
    @RunWith(JUnitPlatform.class)
    public class JupiterTest {
    @Test
    void someTest() {
    // test something
    }
    }

    View Slide

  20. JUnitPlatform Runner in suite mode
    @RunWith(JUnitPlatform.class)
    @SelectPackages("com.acme")
    @IncludeEngines({"junit-jupiter", "junit-vintage"})
    public class JUnit4SuiteDemo {
    // this class can be run using JUnit 4
    }

    View Slide

  21. Test Execution
    • IDEs:
    • IntelliJ supports JUnit 5 ≥ M2 since 2016.2
    • Eclipse support is available on a branch (see Instructions).

    Official release slated for Oxygen.1.
    • Interim solution for other IDEs: JUnitPlatform Runner
    • Gradle/Maven: Plugin/Provider available
    • see https://github.com/junit-team/junit5-samples
    • Manually: ConsoleLauncher

    View Slide

  22. Compatibility
    • Backward compatibility
    (junit-vintage-engine)
    enables gradual migration
    of tests to Jupiter API
    • Forward compatibility
    (JUnitPlatform Runner)
    allows test execution with
    “old” tools

    View Slide

  23. Extensions

    View Slide

  24. Registration via @ExtendWith
    • Annotate your test classes or methods to register
    extensions
    • Supports an arbitrary number of extensions at the
    same time
    • May be used as a meta-annotation

    View Slide

  25. DEMO

    View Slide

  26. Extension Points
    • Conditional Test Execution
    • ContainerExecutionCondition
    • TestExecutionCondition
    • General Purpose
    • TestInstancePostProcessor
    • TestExecutionExceptionHandler
    • ParameterResolver
    • Test Lifecycle Callbacks
    • BeforeAllCallback
    • BeforeEachCallback
    • BeforeTestExecutionCallback
    • AfterTestExecutionCallback
    • AfterEachCallback
    • AfterAllCallback

    View Slide

  27. Roadmap

    View Slide

  28. M4: @ParameterizedTest
    class ParameterizedTests {
    @ParameterizedTest @CsvSource({ "foo, 1", "bar, 2" })
    void testWithParametersFromAnnotation(String parameter, int i) {
    // test something
    }
    @ParameterizedTest @MethodSource(names = "providerMethod")
    void testWithParametersFromMethods(String parameter) {
    }
    static Iterable providerMethod() { return asList("foo", "bar"); }
    @ParameterizedTest @CsvFileSource(resources = { "foo.csv", "/bar.csv" })
    void testWithParametersFromFile(String parameter) {
    }
    }

    View Slide

  29. M4: @RepeatedTest
    @RepeatedTest(10)
    void repeatedTest() {
    // ...
    }

    View Slide

  30. Roadmap to GA
    • 5.0.0-M4 (April 2017): Parameterized/RepeatedTests
    • 5.0.0-M5 (?) (May 2017): Java 9 compatibility
    • 5.0.0-RC1 (June 2017): Last fixes before GA
    • 5.0.0 (July 2017): GA

    View Slide

  31. Getting Started
    User Guide:

    http://junit.org/junit5/docs/current/user-guide/
    Sample projects for Gradle and Maven:

    https://github.com/junit-team/junit5-samples
    Javadoc:

    http://junit.org/junit5/docs/current/api/

    View Slide

  32. Wanted: Feedback!
    Website:

    http://junit.org/junit5/
    Code & Issues:

    https://github.com/junit-team/junit5/
    Twitter:

    https://twitter.com/junitteam

    View Slide