New Opportunities for Testing on the JVM
@sam_brannen
JUnit
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
Agenda
•  Impetus for Change
•  JUnit 5
•  Spring 5
•  Q & A
@sam_brannen#JavaOne #JUnit5
Show of hands …
@sam_brannen#JavaOne #JUnit5
Why a new version of JUnit?
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
JUnit 4 Runner API
•  Very powerful
•  In fact, it can do anything
•  But… you can’t combine Runners
•  Parameterized + SpringRunner à no way
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
Thanks!
@sam_brannen#JavaOne #JUnit5
The Kick-off Team
@sam_brannen#JavaOne #JUnit5
JUnit 5
@sam_brannen#JavaOne #JUnit5
Roadmap
•  Prototype à December 2nd, 2015
•  5.0.0-ALPHA à February 1st, 2016
•  6 Milestones à July 2016 – July 2017
•  2-3 Release Candidates à July 2017 – August 2017
•  5.0.0 GA à September 10th, 2017 ✅
•  5.0.1 à Today! (October 3rd, 2017) ✅
@sam_brannen#JavaOne #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)
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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…
@sam_brannen#JavaOne #JUnit5
Third-party TestEngines
•  Specsy
•  Spek
•  Cucumber
•  Drools Scenario
•  jqwik
source: https://github.com/junit-team/junit5/wiki/Third-party-Extensions
P L A T F O R M
J U P I T E RV I N T A G E
P A R T Y
T H I R D
PLATFORM
JUPITER
VINTAGE
PARTY
THIRD
@sam_brannen#JavaOne #JUnit5
IDEs and Build Tools
•  IntelliJ: ✅ IDEA 2016.2+
•  Eclipse: ✅ Eclipse Oxygen 4.7.1a (to be released next week)
•  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
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
Extension APIs
•  BeforeAllCallback
•  BeforeEachCallback
•  BeforeTestExecutionCallback
•  AfterTestExecutionCallback
•  AfterEachCallback
•  AfterAllCallback
•  TestExecutionExceptionHandler
•  ExecutionCondition
•  TestInstancePostProcessor
•  ParameterResolver
•  TestTemplateInvocationContextProvider
Lifecycle Callbacks
Dependency Injection
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
Annotations
•  @Test / @TestFactory and @Testable for TestEngine implementors
•  @RepeatedTest / @ParameterizedTest and @TestTemplate
•  @Nested
•  @TestInstance
•  @BeforeAll / @AfterAll
•  @BeforeEach / @AfterEach
•  @DisplayName
•  @Tag
•  @Disabled
@sam_brannen#JavaOne #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 bug in 5.0.0; fixed in 5.0.1
@sam_brannen#JavaOne #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.
@sam_brannen#JavaOne #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( ? , () -> {} ); – λ
@sam_brannen#JavaOne #JUnit5
LIVE CODING DEMO
from JUnit 4 to JUnit Jupiter
@sam_brannen#JavaOne #JUnit5
Tagging
@Tag("fast")
@Test
void myFastTest() {
}
•  Declare @Tag on a test interface, class, or method
@sam_brannen#JavaOne #JUnit5
Custom Tags
@Target(METHOD)
@Retention(RUNTIME)
@Tag("fast")
public @interface Fast {
}
•  Declare @Tag as a meta-annotation
@Fast
@Test
void myFastTest() {}
@sam_brannen#JavaOne #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() {
}
@sam_brannen#JavaOne #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 😱
@sam_brannen#JavaOne #JUnit5
Dependency Injection
•  Extension Model meets Programming Model
•  ParameterResolver extension API
•  resolves parameters for constructors or method
o  not just @Test and lifecycle methods
•  can register multiple simultaneously
•  only one wins
•  Use cases
•  server URL, DataSource, Spring ApplicationContext, etc.
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
LIVE CODING DEMO
tags, display names, and dependency injection
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
Interface Default Methods
•  Introduces the concept of a test interface
•  Enables 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
@sam_brannen#JavaOne #JUnit5
DEMO
default methods
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
DEMO
nested test classes
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #JUnit5
@RepeatedTest in Action
@RepeatedTest(5)
void repeatedTest(RepetitionInfo repetitionInfo) {
assertEquals(5, repetitionInfo.getTotalRepetitions());
}
@RepeatedTest(
value = 5,
name = "Wiederholung {currentRepetition} von {totalRepetitions}”
)
void repeatedTestInGerman() {
// ...
}
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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));
}
@sam_brannen#JavaOne #JUnit5
LIVE CODING DEMO
repeated and parameterized tests
@sam_brannen#JavaOne #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 🤓
@sam_brannen#JavaOne #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)));
}
@sam_brannen#JavaOne #JUnit5
DEMO
dynamic tests
@sam_brannen#JavaOne #JUnit5
What’s Missing?
•  Scenario tests
•  Ordering
•  Parallel execution
•  Execution in user-defined thread
•  Declarative test suites for the JUnit Platform
•  Java 9 module-path scanning
•  …
@sam_brannen#JavaOne #JUnit5
Spring 5 + JUnit 5
@sam_brannen#JavaOne #JUnit5
Spring Support for JUnit Jupiter
•  Fully integrated in Spring Framework 5.0!
•  released last week 😎
•  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
@sam_brannen#JavaOne #JUnit5
Configuring JUnit Jupiter with Spring
•  SpringExtension
•  @ExtendWith(SpringExtension.class)
•  @SpringJUnitConfig
•  @ContextConfiguration + SpringExtension
•  @SpringJUnitWebConfig
•  @SpringJUnitConfig + @WebAppConfiguration
•  @EnabledIf / @DisabledIf
•  SpEL expression evaluation for conditional execution
@sam_brannen#JavaOne #JUnit5
DEMO
Spring 5 and JUnit Jupiter
@EnabledOnMac / @DisabledOnMac
@sam_brannen#JavaOne #JUnit5
Spring Boot 1.4 + JUnit 5 – Custom Config
@Target(TYPE)
@Retention(RUNTIME)
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = MOCK)
@AutoConfigureMockMvc
@Transactional
public @interface SpringEventsWebTest {
}
•  @SpringBootTest + @AutoConfigureMockMvc + @ExtendWith(SpringExtension.class)
@sam_brannen#JavaOne #JUnit5
Spring Boot 1.4 + 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
@sam_brannen#JavaOne #JUnit5
In closing …
@sam_brannen#JavaOne #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
@sam_brannen#JavaOne #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, …
@sam_brannen#JavaOne #JUnit5
Additional JUnit 5 Talks @ JavaOne 2017
JUnit 5 BOF
Tuesday, Oct 03, 6:45 p.m. - 7:30 p.m. | Moscone West - Room 2016
JUnit5: Features, Architecture, and Extensibility
Wednesday, Oct 04, 2:45 p.m. - 3:30 p.m. | Moscone West - Room 2009
@sam_brannen#JavaOne #JUnit5
Demos Used in this Presentation
https://github.com/sbrannen/junit5-demo
@sam_brannen#JavaOne #JUnit5
Q & A
Sam Brannen
JUnit

JUnit 5 - New Opportunities for Testing on the JVM

  • 1.
    New Opportunities forTesting on the JVM @sam_brannen JUnit
  • 2.
    @sam_brannen#JavaOne #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
  • 3.
    @sam_brannen#JavaOne #JUnit5 Experts inSpring 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
  • 4.
    @sam_brannen#JavaOne #JUnit5 Agenda •  Impetusfor Change •  JUnit 5 •  Spring 5 •  Q & A
  • 5.
  • 6.
  • 7.
    @sam_brannen#JavaOne #JUnit5 Impetus forChange •  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
  • 8.
    @sam_brannen#JavaOne #JUnit5 JUnit 4Runner API •  Very powerful •  In fact, it can do anything •  But… you can’t combine Runners •  Parameterized + SpringRunner à no way
  • 9.
    @sam_brannen#JavaOne #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
  • 10.
    @sam_brannen#JavaOne #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
  • 11.
  • 12.
  • 13.
  • 14.
    @sam_brannen#JavaOne #JUnit5 Roadmap •  Prototypeà December 2nd, 2015 •  5.0.0-ALPHA à February 1st, 2016 •  6 Milestones à July 2016 – July 2017 •  2-3 Release Candidates à July 2017 – August 2017 •  5.0.0 GA à September 10th, 2017 ✅ •  5.0.1 à Today! (October 3rd, 2017) ✅
  • 15.
    @sam_brannen#JavaOne #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)
  • 16.
    @sam_brannen#JavaOne #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
  • 17.
    @sam_brannen#JavaOne #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
  • 18.
    @sam_brannen#JavaOne #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
  • 19.
    @sam_brannen#JavaOne #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…
  • 20.
    @sam_brannen#JavaOne #JUnit5 Third-party TestEngines • Specsy •  Spek •  Cucumber •  Drools Scenario •  jqwik source: https://github.com/junit-team/junit5/wiki/Third-party-Extensions
  • 21.
    P L AT F O R M J U P I T E RV I N T A G E P A R T Y T H I R D
  • 22.
  • 23.
    @sam_brannen#JavaOne #JUnit5 IDEs andBuild Tools •  IntelliJ: ✅ IDEA 2016.2+ •  Eclipse: ✅ Eclipse Oxygen 4.7.1a (to be released next week) •  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
  • 24.
    @sam_brannen#JavaOne #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
  • 25.
    @sam_brannen#JavaOne #JUnit5 Extension APIs • BeforeAllCallback •  BeforeEachCallback •  BeforeTestExecutionCallback •  AfterTestExecutionCallback •  AfterEachCallback •  AfterAllCallback •  TestExecutionExceptionHandler •  ExecutionCondition •  TestInstancePostProcessor •  ParameterResolver •  TestTemplateInvocationContextProvider Lifecycle Callbacks Dependency Injection
  • 26.
    @sam_brannen#JavaOne #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
  • 27.
    @sam_brannen#JavaOne #JUnit5 Annotations •  @Test/ @TestFactory and @Testable for TestEngine implementors •  @RepeatedTest / @ParameterizedTest and @TestTemplate •  @Nested •  @TestInstance •  @BeforeAll / @AfterAll •  @BeforeEach / @AfterEach •  @DisplayName •  @Tag •  @Disabled
  • 28.
    @sam_brannen#JavaOne #JUnit5 JUnit 4Rule 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 bug in 5.0.0; fixed in 5.0.1
  • 29.
    @sam_brannen#JavaOne #JUnit5 Assertions org.junit.jupiter.api.Assertions •  Limitedset 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.
  • 30.
    @sam_brannen#JavaOne #JUnit5 Assumptions org.junit.jupiter.api.Assumptions •  Limitedset of core assumptions •  For aborting tests mid-flight •  Otherwise, favor a custom ExecutionCondition for skipping •  assumeTrue() / assumeFalse() •  BooleanSupplier, Supplier<String> – λ •  assumingThat( ? , () -> {} ); – λ
  • 31.
    @sam_brannen#JavaOne #JUnit5 LIVE CODINGDEMO from JUnit 4 to JUnit Jupiter
  • 32.
    @sam_brannen#JavaOne #JUnit5 Tagging @Tag("fast") @Test void myFastTest(){ } •  Declare @Tag on a test interface, class, or method
  • 33.
    @sam_brannen#JavaOne #JUnit5 Custom Tags @Target(METHOD) @Retention(RUNTIME) @Tag("fast") public@interface Fast { } •  Declare @Tag as a meta-annotation @Fast @Test void myFastTest() {}
  • 34.
    @sam_brannen#JavaOne #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() { }
  • 35.
    @sam_brannen#JavaOne #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 😱
  • 36.
    @sam_brannen#JavaOne #JUnit5 Dependency Injection • Extension Model meets Programming Model •  ParameterResolver extension API •  resolves parameters for constructors or method o  not just @Test and lifecycle methods •  can register multiple simultaneously •  only one wins •  Use cases •  server URL, DataSource, Spring ApplicationContext, etc.
  • 37.
    @sam_brannen#JavaOne #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
  • 38.
    @sam_brannen#JavaOne #JUnit5 LIVE CODINGDEMO tags, display names, and dependency injection
  • 39.
    @sam_brannen#JavaOne #JUnit5 Conditional TestExecution •  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
  • 40.
    @sam_brannen#JavaOne #JUnit5 Interface DefaultMethods •  Introduces the concept of a test interface •  Enables 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
  • 41.
  • 42.
    @sam_brannen#JavaOne #JUnit5 Nested TestClasses •  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
  • 43.
  • 44.
    @sam_brannen#JavaOne #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
  • 45.
    @sam_brannen#JavaOne #JUnit5 @RepeatedTest inAction @RepeatedTest(5) void repeatedTest(RepetitionInfo repetitionInfo) { assertEquals(5, repetitionInfo.getTotalRepetitions()); } @RepeatedTest( value = 5, name = "Wiederholung {currentRepetition} von {totalRepetitions}” ) void repeatedTestInGerman() { // ... }
  • 46.
    @sam_brannen#JavaOne #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
  • 47.
    @sam_brannen#JavaOne #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
  • 48.
    @sam_brannen#JavaOne #JUnit5 @ParameterizedTest inAction @ParameterizedTest @ValueSource(strings = { "mom", "dad", "radar", "racecar", "able was I ere I saw elba" }) void palindromes(String candidate) { assertTrue(isPalindrome(candidate)); }
  • 49.
    @sam_brannen#JavaOne #JUnit5 LIVE CODINGDEMO repeated and parameterized tests
  • 50.
    @sam_brannen#JavaOne #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 🤓
  • 51.
    @sam_brannen#JavaOne #JUnit5 Dynamic Testsin 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))); }
  • 52.
  • 53.
    @sam_brannen#JavaOne #JUnit5 What’s Missing? • Scenario tests •  Ordering •  Parallel execution •  Execution in user-defined thread •  Declarative test suites for the JUnit Platform •  Java 9 module-path scanning •  …
  • 54.
  • 55.
    @sam_brannen#JavaOne #JUnit5 Spring Supportfor JUnit Jupiter •  Fully integrated in Spring Framework 5.0! •  released last week 😎 •  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
  • 56.
    @sam_brannen#JavaOne #JUnit5 Configuring JUnitJupiter with Spring •  SpringExtension •  @ExtendWith(SpringExtension.class) •  @SpringJUnitConfig •  @ContextConfiguration + SpringExtension •  @SpringJUnitWebConfig •  @SpringJUnitConfig + @WebAppConfiguration •  @EnabledIf / @DisabledIf •  SpEL expression evaluation for conditional execution
  • 57.
    @sam_brannen#JavaOne #JUnit5 DEMO Spring 5and JUnit Jupiter @EnabledOnMac / @DisabledOnMac
  • 58.
    @sam_brannen#JavaOne #JUnit5 Spring Boot1.4 + JUnit 5 – Custom Config @Target(TYPE) @Retention(RUNTIME) @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = MOCK) @AutoConfigureMockMvc @Transactional public @interface SpringEventsWebTest { } •  @SpringBootTest + @AutoConfigureMockMvc + @ExtendWith(SpringExtension.class)
  • 59.
    @sam_brannen#JavaOne #JUnit5 Spring Boot1.4 + 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
  • 60.
  • 61.
    @sam_brannen#JavaOne #JUnit5 JUnit 5Resources 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
  • 62.
    @sam_brannen#JavaOne #JUnit5 Spring Resources SpringFramework à 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, …
  • 63.
    @sam_brannen#JavaOne #JUnit5 Additional JUnit5 Talks @ JavaOne 2017 JUnit 5 BOF Tuesday, Oct 03, 6:45 p.m. - 7:30 p.m. | Moscone West - Room 2016 JUnit5: Features, Architecture, and Extensibility Wednesday, Oct 04, 2:45 p.m. - 3:30 p.m. | Moscone West - Room 2009
  • 64.
    @sam_brannen#JavaOne #JUnit5 Demos Usedin this Presentation https://github.com/sbrannen/junit5-demo
  • 65.