$30 off During Our Annual Pro Sale. View Details »

JUnit 5 @ Devoxx BE 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
  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
  3. @marcphilipp & @sam_brannen #Devoxx #JUnit5 > 3000 employees > 18

    offices worldwide SaaS AWS, Azure microservices Spring Boot Docker DevOps
  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
  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
  6. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Agenda •  Impetus for Change

    •  JUnit 5 •  Demos •  Live Coding •  Spring 5 •  Q & A
  7. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Show of hands …

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

    JUnit?
  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 …
  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
  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
  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
  13. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Thanks!

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

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

  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
  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)
  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
  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
  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
  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…
  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
  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
  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
  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
  26. @marcphilipp & @sam_brannen #Devoxx #JUnit5 So, what is JUnit Jupiter?

  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
  28. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Extension APIs •  BeforeAllCallback • 

    BeforeEachCallback •  BeforeTestExecutionCallback •  AfterTestExecutionCallback •  AfterEachCallback •  AfterAllCallback •  TestExecutionExceptionHandler •  ExecutionCondition •  TestInstancePostProcessor •  ParameterResolver •  TestTemplateInvocationContextProvider Lifecycle Callbacks Dependency Injection
  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
  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
  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
  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<String> à λ for lazy failure message evaluation •  message is now the last parameter •  For more power, use AssertJ, Hamcrest, etc.
  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<String> – λ •  assumingThat( ? , () -> {} ); – λ
  34. @marcphilipp & @sam_brannen #Devoxx #JUnit5 LIVE CODING DEMO from JUnit

    4 to JUnit Jupiter
  35. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Tagging @Tag("fast") @Test void myFastTest()

    { } •  Declare @Tag on a test interface, class, or method
  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() {}
  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() { }
  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
  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.
  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
  41. @marcphilipp & @sam_brannen #Devoxx #JUnit5 What’s the significance of @Disabled?

  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
  43. @marcphilipp & @sam_brannen #Devoxx #JUnit5 LIVE CODING DEMO tags, display

    names, dependency injection, & conditions
  44. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Testing Traits?

  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
  46. @marcphilipp & @sam_brannen #Devoxx #JUnit5 DEMO default methods

  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
  48. @marcphilipp & @sam_brannen #Devoxx #JUnit5 DEMO nested test classes

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

  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
  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() { // ... }
  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
  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
  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)); }
  55. @marcphilipp & @sam_brannen #Devoxx #JUnit5 DEMO repeated and parameterized tests

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

  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
  58. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Dynamic Tests in Action @TestFactory

    Stream<DynamicTest> 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))); }
  59. @marcphilipp & @sam_brannen #Devoxx #JUnit5 DEMO dynamic tests

  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 •  …
  61. @marcphilipp & @sam_brannen #Devoxx #JUnit5 LIVE CODING DEMO custom extensions

    •  logging •  timing •  conditions
  62. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Spring 5 + JUnit 5

  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
  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
  65. @marcphilipp & @sam_brannen #Devoxx #JUnit5 DEMO Spring 5 and JUnit

    Jupiter @EnabledOnMac / @DisabledOnMac
  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)
  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
  68. @marcphilipp & @sam_brannen #Devoxx #JUnit5 In closing …

  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
  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, …
  71. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Demos Used in this Presentation

    https://github.com/sbrannen/junit5-demo
  72. @marcphilipp & @sam_brannen #Devoxx #JUnit5 JUnit 5 BOF @ Devoxx

    2017 In 20 minutes in BOF room #2 (19:00 – 20:00)
  73. @marcphilipp & @sam_brannen #Devoxx #JUnit5 Q & A Marc Philipp

    Sam Brannen JUnit