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

JUnit 5 @ Devoxx BE 2017

Marc Philipp
November 08, 2017

JUnit 5 @ Devoxx BE 2017

Marc Philipp

November 08, 2017
Tweet

More Decks by Marc Philipp

Other Decks in Programming

Transcript

  1. The New Testing Framework for Java
    and Testing Platform for the JVM
    @marcphilipp & @sam_brannen
    JUnit

    View full-size slide

  2. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Marc Philipp
    •  Software Engineer @ LogMeIn in Karlsruhe, Germany
    •  Consultant, trainer, coach in a former life
    •  JUnit Maintainer since 2012
    •  JUnit’s “Keeper of the Green Bar” for 2016 and 2017
    •  Twitter: @marcphilipp
    •  GitHub: marcphilipp
    •  Web: marcphilipp.de

    View full-size slide

  3. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    > 3000 employees
    > 18 offices
    worldwide
    SaaS
    AWS, Azure
    microservices
    Spring Boot
    Docker
    DevOps

    View full-size slide

  4. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Sam Brannen
    •  Spring and Java Consultant
    •  Trainer, Coach, …
    •  Hardcore developer at heart
    •  Java Developer for about 20 years
    •  Spring Framework Core Committer since 2007
    •  JUnit 5 Core Committer since October 2015

    View full-size slide

  5. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Experts in Spring and Enterprise Java
    Areas of expertise
    •  Spring *
    •  JUnit 5
    •  Java EE
    •  Software Architecture
    •  Code Reviews
    Where you find us
    •  Zurich, Switzerland
    •  @swiftmind
    •  http://www.swiftmind.com

    View full-size slide

  6. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Agenda
    •  Impetus for Change
    •  JUnit 5
    •  Demos
    •  Live Coding
    •  Spring 5
    •  Q & A

    View full-size slide

  7. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Show of hands …

    View full-size slide

  8. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Why a new version of JUnit?

    View full-size slide

  9. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Impetus for Change
    •  JUnit 4.0 was released a decade ago
    •  a lot has changed since then…
    •  testing needs have matured
    •  expectations have grown
    •  Modularity à big ball of mud (i.e., only THE junit.jar)
    •  Test discovery and execution à tightly coupled
    •  Extensibility à lot of room for improvement
    •  Let’s not forget Java 8 and Java 9 and …

    View full-size slide

  10. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 4 Runner API
    •  Very powerful
    •  In fact, it can do anything
    •  But… you can’t combine Runners
    •  Parameterized + SpringRunner à no way

    View full-size slide

  11. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 4… Rules… are meant to be broken
    •  JUnit 4.7: MethodRule à @Rule
    •  JUnit 4.9: TestRule à @Rule / @ClassRule
    •  Great for simple use cases
    •  Can even be combined
    •  But… a single rule can’t be used for method-level and class-level callbacks
    •  Plus… zero support for instance-level callbacks
    •  Case in point: SpringClassRule / SpringMethodRule

    View full-size slide

  12. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit Lambda – Crowdfunding Campaign
    •  Initiated by Johannes Link and Marc Philipp
    •  Later joined by Matthias Merdes, Stefan Bechtold, &
    Sam Brannen
    •  Ran from July to October 2015
    •  Raised 53,937 Euros from 474 individuals and
    companies
    •  4 companies donated 6 weeks of developer time

    View full-size slide

  13. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Thanks!

    View full-size slide

  14. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    The Kick-off Team

    View full-size slide

  15. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    So, what is JUnit 5?

    View full-size slide

  16. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Roadmap
    •  Prototype à December 2nd, 2015
    •  5.0.0-ALPHA à February 1st, 2016
    •  Milestones & RCs à July 2016 – August 2017
    •  5.0.0 GA à September 10th, 2017 ✅
    •  5.0.1 à October 3rd, 2017 ✅
    •  5.0.2 & 5.1 M1 à soon

    View full-size slide

  17. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 5 – in a Nutshell
    •  Modular
    •  Extensible
    •  Modern
    •  Forward and backward compatible
    •  JUnit Platform supports JUnit 3.8, JUnit 4, and JUnit 5
    •  New testing frameworks can be run with JUnit 4 infrastructure
    o 
    @RunWith(JUnitPlatform.class)

    View full-size slide

  18. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 5 – Java Versions
    •  Java 8
    •  baseline
    •  but can be used to test application code compiled against previous JDK versions
    •  Java 9
    •  #WorksFineOnJDK9
    •  every artifact has a stable AUTOMATIC-MODULE-NAME
    •  module-path scanning support coming in 5.1
    •  Java 10
    •  We just started building against EA builds last week

    View full-size slide

  19. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 5 = Platform + Jupiter + Vintage
    •  JUnit Platform 1.0.0
    •  Foundation for launching testing frameworks on the JVM
    •  Launcher and TestEngine APIs
    •  ConsoleLauncher, Gradle plugin, Maven Surefire provider
    •  JUnit Jupiter 5.0.0
    •  New programming model and extension model for JUnit 5
    •  JUnit Vintage 4.12.0
    •  TestEngine for running JUnit 3 and JUnit 4 based tests
    Revolutionary
    Evolutionary
    Necessary

    View full-size slide

  20. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Launcher API
    •  Used by IDEs and build tools to launch the framework
    •  Central API for discovering and executing tests via one or more engines
    •  LauncherDiscoveryRequest
    •  selectors and filters
    •  Feedback provided via the TestExecutionListener API
    •  ConsoleLauncher for command-line support

    View full-size slide

  21. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    TestEngine API
    •  Test engine discovers and executes tests
    •  for a particular programming model
    •  Automatic registration via Java’s ServiceLoader mechanism
    •  JupiterTestEngine
    •  VintageTestEngine
    •  Implement your own…

    View full-size slide

  22. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Third-party TestEngines
    •  Specsy
    •  Spek
    •  Cucumber
    •  Drools Scenario
    •  jqwik
    source: https://github.com/junit-team/junit5/wiki/Third-party-Extensions

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  25. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    IDEs and Build Tools
    •  IntelliJ: ✅ IDEA 2016.2+ (2017.2.5)
    •  Eclipse: ✅ Eclipse Oxygen 4.7.1a
    •  NetBeans:
    •  Gradle: interim solution from JUnit Team
    •  to be taken over by Gradle team (end of 2017)
    •  Android JUnit 5: third-party Android support
    •  Maven: interim solution from JUnit Team
    •  being taken over by Maven Surefire team
    See user guide and
    sample apps for examples

    View full-size slide

  26. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    So, what is JUnit Jupiter?

    View full-size slide

  27. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit Jupiter – Extension Model
    •  Extension
    •  marker interface
    •  org.junit.jupiter.api.extension
    •  package containing all extension APIs
    •  implement as many as you like
    •  @ExtendWith(...)
    •  used to register one or more extensions
    •  interface, class, or method level
    o  or as a meta-annotation

    View full-size slide

  28. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Extension APIs
    •  BeforeAllCallback
    •  BeforeEachCallback
    • 
    BeforeTestExecutionCallback
    • 
    AfterTestExecutionCallback
    •  AfterEachCallback
    •  AfterAllCallback
    •  TestExecutionExceptionHandler
    •  ExecutionCondition
    •  TestInstancePostProcessor
    •  ParameterResolver
    •  TestTemplateInvocationContextProvider
    Lifecycle Callbacks
    Dependency Injection

    View full-size slide

  29. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit Jupiter – Programming Model
    org.junit.jupiter.api (org.junit.jupiter.params)
    •  Annotations and meta-annotations
    •  Assertions and Assumptions
    •  Custom display names
    •  Visibility
    •  Tagging
    •  Conditional test execution
    •  Dependency injection for constructors and methods
    •  Lambda expressions and method references
    •  Interface default methods
    •  Nested test classes
    •  Repeated tests, parameterized tests, dynamic tests

    View full-size slide

  30. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Annotations
    •  @Test / @TestFactory and @Testable for TestEngine implementors
    •  @RepeatedTest / @ParameterizedTest and @TestTemplate
    •  @Nested
    •  @TestInstance
    •  @BeforeAll / @AfterAll
    •  @BeforeEach / @AfterEach
    •  @DisplayName
    •  @Tag
    •  @Disabled

    View full-size slide

  31. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 4 Rule Migration Support
    •  @EnableRuleMigrationSupport
    o  located in experimental junit-jupiter-migrationsupport module
    o  registers 3 extensions for JUnit Jupiter
    •  ExternalResourceSupport
    o  TemporaryFolder, etc.
    •  VerifierSupport
    o  ErrorCollector, etc.
    •  ExpectedExceptionSupport
    o  ExpectedException
    o  minor bugs in 5.0.0; fixed in 5.0.1and 5.0.2

    View full-size slide

  32. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Assertions
    org.junit.jupiter.api.Assertions
    •  Limited set of core assertions
    •  assertEquals(), assertNotNull(), etc.
    •  assertThrows() – λ
    •  assertTimeout() and assertTimeoutPreemptively() – λ
    •  assertAll() – λ
    •  Supplier à λ for lazy failure message evaluation
    •  message is now the last parameter
    •  For more power, use AssertJ, Hamcrest, etc.

    View full-size slide

  33. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Assumptions
    org.junit.jupiter.api.Assumptions
    •  Limited set of core assumptions
    •  For aborting tests mid-flight
    •  Otherwise, favor a custom ExecutionCondition for skipping
    •  assumeTrue() / assumeFalse()
    •  BooleanSupplier, Supplier – λ
    •  assumingThat( ? , () -> {} ); – λ

    View full-size slide

  34. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    LIVE CODING DEMO
    from JUnit 4 to JUnit Jupiter

    View full-size slide

  35. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Tagging
    @Tag("fast")
    @Test
    void myFastTest() {
    }
    •  Declare @Tag on a test interface, class, or method

    View full-size slide

  36. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Custom Tags
    @Target(METHOD)
    @Retention(RUNTIME)
    @Tag("fast")
    public @interface Fast {
    }
    •  Declare @Tag as a meta-annotation
    @Fast
    @Test
    void myFastTest() {}

    View full-size slide

  37. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Composed Tags
    @Target(METHOD)
    @Retention(RUNTIME)
    @Tag("fast")
    @Test
    public @interface FastTest {
    }
    •  Declare @Tag as a meta-annotation with other annotations (JUnit, Spring, etc.)
    @FastTest
    void myFastTest() {
    }

    View full-size slide

  38. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Test Names
    •  Names default to test class or test method names
    •  characters limited based on Java syntax
    •  Custom display names à @DisplayName
    •  Can contain spaces, special chars, and even emoji

    View full-size slide

  39. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Dependency Injection
    •  Extension Model meets Programming Model
    •  ParameterResolver extension API
    •  resolves parameters for @Test and lifecycle methods
    o  and even constructors
    •  can register multiple simultaneously
    •  only one wins
    •  Use cases
    •  server URL, DataSource, Spring ApplicationContext, etc.

    View full-size slide

  40. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    TestInfo
    •  TestInfo: inject into constructor, @Test, @BeforeEach, etc.
    •  access display name, tags, class, method
    •  TestInfoParameterResolver
    •  eating our own dog food ;-)
    •  See also:
    •  RepetitionInfo for @RepeatedTest
    •  TestReporter
    •  MockitoExtension
    •  SpringExtension

    View full-size slide

  41. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    What’s the significance of @Disabled?

    View full-size slide

  42. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Conditional Test Execution
    •  Extension Model meets Programming Model
    •  ExecutionCondition
    •  @Disabled
    •  DisabledCondition
    •  eating our own dog food ;-)
    •  Deactivate via Launcher, system property, or junit-platform.properties file
    •  junit.conditions.deactivate = org.junit.*
    Game Changer

    View full-size slide

  43. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    LIVE CODING DEMO
    tags, display names, dependency injection, & conditions

    View full-size slide

  44. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Testing Traits?

    View full-size slide

  45. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Interface Default Methods
    •  Enables the concept of a test interface
    •  leading to multiple inheritance in tests
    •  a.k.a., testing traits
    •  @BeforeAll / @AfterAll
    •  if using @TestInstance(Lifecyle.PER_CLASS)
    •  @BeforeEach / @AfterEach
    •  @Test / @RepeatedTest / @ParameterizedTest / @TestFactory
    •  @Tag
    •  @ExtendWith
    •  See StringTests and TestInterfaceDemo examples in user guide

    View full-size slide

  46. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    DEMO
    default methods

    View full-size slide

  47. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Nested Test Classes
    •  Enables logical, hierarchical grouping of test classes
    •  with shared initialization and state from outer classes
    •  Declare @Nested on non-static nested classes
    •  i.e., inner classes
    •  You can even combine nested classes and test interfaces
    •  See TestingAStack example in user guide and Bowling Game Kata by Tim Riemer

    View full-size slide

  48. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    DEMO
    nested test classes

    View full-size slide

  49. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Test Templates?

    View full-size slide

  50. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Repeated Tests
    •  Annotate a method with @RepeatedTest instead of @Test
    o  and specify the number of repetitions
    •  Optionally have the RepetitionInfo injected as a method parameter
    •  Optionally override the display name

    View full-size slide

  51. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    @RepeatedTest in Action
    @RepeatedTest(5)
    void repeatedTest(RepetitionInfo repetitionInfo) {
    assertEquals(5, repetitionInfo.getTotalRepetitions());
    }
    @RepeatedTest(
    value = 5,
    name = "Wiederholung {currentRepetition} von {totalRepetitions}”
    )
    void repeatedTestInGerman() {
    // ...
    }

    View full-size slide

  52. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Parameterized Tests (junit-jupiter-params)
    •  Annotate a method with @ParameterizedTest instead of @Test
    o  and specify the source of the arguments
    o  optionally override the display name
    •  Sources
    o  @ValueSource: String, int, long, double
    o  @EnumSource
    o  @MethodSource
    o  @CsvSource & @CsvFileSource
    o  @ArgumentsSource & custom ArgumentsProvider

    View full-size slide

  53. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Argument Conversion
    •  Implicit conversion
    o  Primitive types and their wrappers
    o  Enums
    o  java.time types (JSR-310)
    •  Explicit conversion
    o  @ConvertWith and custom ArgumentConverter
    o  @JavaTimeConversionPattern built-in support for JSR-310

    View full-size slide

  54. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    @ParameterizedTest in Action
    @ParameterizedTest
    @ValueSource(strings = {
    "mom",
    "dad",
    "radar",
    "racecar",
    "able was I ere I saw elba"
    })
    void palindromes(String candidate) {
    assertTrue(isPalindrome(candidate));
    }

    View full-size slide

  55. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    DEMO
    repeated and parameterized tests

    View full-size slide

  56. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Lambdas as Tests?

    View full-size slide

  57. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Dynamic Tests
    •  Conventional tests are static (i.e., known at compile time)
    •  @Test
    •  A DynamicTest is registered at runtime – λ
    •  as lambda expression in a stream, collection, etc.
    •  by a method annotated with @TestFactory
    •  Can also register a DynamicContainer for dynamic nesting
    •  Somewhat analogous to parameterized tests
    •  just more… dynamic

    View full-size slide

  58. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Dynamic Tests in Action
    @TestFactory
    Stream dynamicTestsFromIntStream() {
    // Generates tests for the first 10 even integers.
    return IntStream.iterate(0, n -> n + 2)
    .limit(10)
    .mapToObj(n ->
    dynamicTest("test" + n,
    () -> assertTrue(n % 2 == 0)));
    }

    View full-size slide

  59. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    DEMO
    dynamic tests

    View full-size slide

  60. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    What’s Missing?
    •  Scenario tests
    •  Ordering
    •  Parallel execution
    •  Execution in user-defined thread
    •  Declarative and programmatic test suites for the JUnit Platform
    •  Java 9 module-path scanning
    •  …

    View full-size slide

  61. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    LIVE CODING DEMO
    custom extensions
    •  logging
    •  timing
    •  conditions

    View full-size slide

  62. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Spring 5 + JUnit 5

    View full-size slide

  63. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Spring Support for JUnit Jupiter
    •  Fully integrated in Spring Framework 5.0!
    •  Supports all Core Spring TestContext Framework features
    •  Constructor and method injection via @Autowired, @Qualifier, @Value
    •  Conditional test execution via SpEL expressions
    •  ApplicationContext configuration annotations
    •  Also works with Spring Framework 4.3
    https://github.com/sbrannen/spring-test-junit5

    View full-size slide

  64. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Configuring JUnit Jupiter with Spring
    •  SpringExtension
    •  @ExtendWith(SpringExtension.class)
    •  @SpringJUnitConfig
    •  @ContextConfiguration + SpringExtension
    •  @SpringJUnitWebConfig
    •  @SpringJUnitConfig + @WebAppConfiguration
    •  @EnabledIf / @DisabledIf
    •  SpEL expression evaluation for conditional execution

    View full-size slide

  65. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    DEMO
    Spring 5 and JUnit Jupiter
    @EnabledOnMac / @DisabledOnMac

    View full-size slide

  66. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Spring Boot 1.5 + JUnit 5 – Custom Config
    @Target(TYPE)
    @Retention(RUNTIME)
    @ExtendWith(SpringExtension.class)
    @SpringBootTest(webEnvironment = MOCK)
    @AutoConfigureMockMvc
    @Transactional
    public @interface SpringEventsWebTest {
    }
    •  @SpringBootTest + @AutoConfigureMockMvc + @ExtendWith(SpringExtension.class)

    View full-size slide

  67. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Spring Boot 1.5 + JUnit 5 – MockMvc Test
    @SpringEventsWebTest
    class EventsControllerTests {
    @Test
    @DisplayName("Home page should display more than 10 events")
    void listEvents(@Autowired MockMvc mockMvc) throws Exception {
    mockMvc.perform(get("/"))
    .andExpect(view().name("event/list"))
    .andExpect(model().attribute("events",
    hasSize(greaterThan(10))));
    }
    }
    •  @SpringEventsWebTest + method-level DI + MockMvc

    View full-size slide

  68. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    In closing …

    View full-size slide

  69. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 5 Resources
    Project Homepage à http://junit.org/junit5
    User Guide à http://junit.org/junit5/docs/current/user-guide
    Javadoc à http://junit.org/junit5/docs/current/api
    GitHub à https://github.com/junit-team
    Gitter à https://gitter.im/junit-team/junit5
    Stack Overflow à http://stackoverflow.com/tags/junit5

    View full-size slide

  70. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Spring Resources
    Spring Framework à http://projects.spring.io/spring-framework
    Spring Guides à http://spring.io/guides
    Spring JIRA à https://jira.spring.io
    Spring on GitHub à https://github.com/spring-projects/spring-framework
    Stack Overflow à spring, spring-test, spring-mvc, spring-boot, …

    View full-size slide

  71. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Demos Used in this Presentation
    https://github.com/sbrannen/junit5-demo

    View full-size slide

  72. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    JUnit 5 BOF @ Devoxx 2017
    In 20 minutes in BOF room #2 (19:00 – 20:00)

    View full-size slide

  73. @marcphilipp & @sam_brannen
    #Devoxx #JUnit5
    Q & A
    Marc Philipp
    Sam Brannen
    JUnit

    View full-size slide