JUnit 5 @ Devoxx BE 2017

JUnit 5 @ Devoxx BE 2017

956c7d246841e8507a1e1b96842994db?s=128

Marc Philipp

November 08, 2017
Tweet

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