SpringOne Platform 2016: Testing with Spring 4.3, JUnit 5, and Beyond

Speaker: Sam Brannen
Twitter: @sam_brannen

Agenda

  • Spring Events App
  • Spring 4.3
  • JUnit 5
  • Spring 5

Spring Events App

The Spring Events App is a Spring boot powered web app using
Spring Boot 1.4, Spring Framework 5, JUnit 5.

Odds & Ends

  • JUnit 4.12+ required by the Spring TestContext framework (TCF)
  • Support for Primary transaction managers and data sources in TCF
  • @Sql and @Sqlgroup many now be used as meta-annotations:
    • to create custom composed annotations with attribute overrides
    • Same is true for many @Repeatable annotations in Core Spring
  • ReflectionTestUtils automatically unwraps proxies when setting/getting a field

Extending the Spring TextContext Framework

  • The getTestContext() method in TestContextManager is now public
  • New ContextCustomizer and ContextCustomizerFactory SPIs
    • Potentially replaces need for custom ContextLoader
    • Customize ApplicationContext after bean definitions are loaded but before context is refreshed
    • Registered globally by third parties via spring.factories mechanism
    • Enables Spring Boot Test Magic

New Features

  • SpringRunner alias for the SpringJUnit4ClassRunner
    >> @RunWith(SpringRunner.class)
  • @ContextConfiguration can be completely omitted…
    • if default XML or @Configuration is detected
    • Spring Boot test 1.4 even locates your @SpringBootApplication class
  • ApplicationContext cache is now bounded

Preparing for the Future

  • Testing Traits
    • Spring test annotations can be declared on interfaces
    • Combines nicely with Java 8 default methods and JUnit 5
  • Non-public @Transactional test methods: for use with JUnit 5 and TestNG
  • Non-public @BeforeTransaction and @AfterTransaction methods

MockMvc Improvements

  • Expectations on multi-value response headers: HeaderResultMatchers.stringValues(…)
  • Form data equest content (e.g., from a POST) now parsed and used to populate request params
  • Support for Custom HTTP verbs (e.g. WebDAV)
  • Improve Cookie support for HtmlUnit integration

MockMvc – Assert invoked Handler Method

New mock-like methodCall() assertion in HandlerResultMatchers: Assert the @Controller method invoked to handle the response:

    mockMvc.perform(get("/"))
    .andExpect(handler().methodCall(
     on(HomeController.class).showHomePage()));

MockMvc – JSON Prefixes

New support for stripping JSON prefixes from Responses. A prefix is used to prohibit JSON hijacking:

    mockMvc.perform(get("/account/42").accept(APPLICATION_JSON))
    .andExpect(jsonPath("$.pin")
    .prefix("&&enigma&&")
    ...

MockRestServiceServer Improvements

  • Expectations for form data in the request body
  • Specify expectation counts
    • Pass ExpectedCount to the expect() method
    • once(), manyTimes(), times(int), min(int), max(int), between(int, int)
    • verify() and reset() afterwards
  • Specify whether ordering should be ignored: invoke ignoreExpectOrder(true) on the MockResetServiceServerBuilder

JUnit 5: Impetus for Change

  • JUnit 4.0 was released a decade ago
  • Modularity -> big ball of mud (i.e., only THE junit.jar)
  • Test Discovery and execution -> tightly coupled
  • Extensibility -> lot of room for improvement
  • Java 8 support

JUnit 4 Runner API

  • Very Powerful
  • You can do anything
  • But you cannot combine Runners
  • Parameterized + SpringJUnit4ClassRunner -> no way

JUnit 4… Rules… are meant to be broken

  • JUnit 4.7: MethodRule -> @Rule
  • JUnit 4.9: TestRule -> @Rule/@ClassRule

JUnit Lambda

  • Initiated by Johannes Link and Marc Philipp
  • Later joined by Matthias Merdes, Stefan Bechtold, and Sam Brannen

JUnit 5 – Roadmap

  • Prototype – December 2015
  • Alpha – February 2016
  • M1 & M2 – July 2016
  • M3, M4, RC1 – Fall 2016
  • GA – End of 2016… maybe

JUnit 5 – In a Nutshell

  • Modular
  • Extensible
  • Modern
  • Forward & Backward Compatible
    • JUnit Platform supports JUnit 3.8, 4 and 5
    • New testing frameworks can be run with JUnit 4 infrastructure:
      @RunWith(JUnitPlatform.class)

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 old stuff

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

TestEngine API

  • aka, Runner in JUnit 4
  • Test engine discovers and executes tests for a particular programming model
  • Automatic registration via Java’s ServiceLoader mechanism
  • JupiterTestEngine
  • VintageTestEngine
  • Implement your own…

Extension APIs

  • BeforeAllCallback
  • BeforeEachCallback
  • BeforeTestExecutionCallback
  • AfterTestExecutionCallback
  • AfterEachCallback
  • AfterAllCallback
  • ContainerExecutionCondition & TestExecutionCondition
  • TestInstancePostProcessor
  • ParameterResolver
  • TestExecutionExceptionHandler

JUnit 5 – Programming Model

org.junit.jupiter.api

  • Annotations & Meta-annotations
  • Assertions & Assumptions
  • Custom Display Names
  • Visibility
  • Tagging
  • Conditional Test Execution
  • DI for Constructors and methods
  • Lambda Expressions and method references
  • Interface default methods
  • Nested test classes
  • Dynamic Tests

Annotations

  • @Test / @TestFactory
  • @BeforeAll / @AfterAll
  • @BeforeEach / @AfterEach
  • @DisplayName
  • @Tag
  • @Disabled
  • @Nested

Assertions

org.junit.jupiter.api.Assertions

  • Limited set of core assertions
  • assertThrows() and expectThrows()
  • assertTimeout()
  • assertAll()

SpringOne Platform 2016: Testing Spring Boot Applications

Speaker: Phil Webb, @phillip_webb
Project: github.com/philwebb/testing-spring-boot-applications

Spring requires no-arg constructors, but there’s no reason that these have to be public: make them protected if it makes sense.

You need tests for:

  1. Domain Layer
  2. Service Layer
  3. Web Layer

@RunWith(SpringRunner.class)

Service Layer Testing

@JSonTest to test JSON format
@MockBean to mock a dependency

Web Layer testing

Test class annotation:
@WebMvcTest


@Autowired
private MockMvc mvc

@MockBean

@AutoConfigureMockMvc
@AutoConfigureTestDatabase