Anda di halaman 1dari 59

Testing with Spring 4.

3,
JUnit 5, and beyond ...
Sam Brannen
@sam_brannen
Sam Brannen
• Spring and Java Consultant @

• Java Developer for over 17 years

• Spring Framework Core Committer since 2007

• Swiss Spring User Group Lead

• Trainer & Conference Speaker

• JUnit 5 Core Committer since October 2015


Your experts for Spring and Enterprise Java

Areas of expertise Where you find us


• Spring * • Zurich, Switzerland
• JUnit • @swiftmind
• Java EE • http://www.swiftmind.com
• Software Architecture
• Code Reviews

3
Agenda
• Spring Events App

• Spring 4.3

• JUnit 5

• Spring 5

• Q&A

4
Show of hands …

5
Spring Events App

6
The Spring Events Example Application
• Spring Boot powered web app
• Spring Boot 1.4, Spring Framework 5, JUnit 5

• Simple POJO domain model: Event

• Transactional service layer

• Spring Data JPA repository layer

• Spring @MVC + Thymeleaf & REST presentation layer

• Spring Security

• https://github.com/sbrannen/spring-events

7
New in Spring Framework 4.3

8
Odds & Ends
• JUnit 4.12+ required by the Spring TestContext Framework (TCF)

• Support for primary transaction managers and data sources in the TCF

• @Sql and @SqlGroup may 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

9
Extending the Spring TestContext 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
the context is refreshed
• Registered globally by third parties via spring.factories mechanism
• Enables Spring Boot Test magic
• Implement to create your own magic 

10
New Features
• SpringRunner alias for the SpringJUnit4ClassRunner
• @RunWith(SpringRunner.class)

• @ContextConfiguration can be completely omitted…


• if default XML, Groovy, or @Configuration is detected
• Spring Boot Test 1.4 even locates your @SpringBootApplication class

• ApplicationContext cache is now bounded


• default maximum size of 32
• Least Recently Used eviction policy
• configured via spring.test.context.cache.maxSize JVM/Spring property

11
Demo
SpringRunner, @ContextConfiguration, bounded cache

12
Preparing for the Future
• Testing Traits
• Spring test annotations can be declared on interfaces
• Combines nicely with Java 8 default methods and JUnit 5
• Enabling so called testing traits in Java

• Non-public @Transactional test methods


• For use with JUnit 5 and TestNG

• Non-public @BeforeTransaction and @AfterTransaction methods


• can also be declared on default methods to create testing traits

13
MockMvc Improvements
• Expectations on multi-value response headers
• HeaderResultMatchers.stringValues(String, String...)

• Form data request content (e.g., from a POST) is now parsed and used to
populate request parameters

• Support for custom HTTP verbs (e.g., WebDAV)


• MockMvcRequestBuilders.request(String methodName, URI uri)

• Improved Cookie support for HtmlUnit integration

14
MockMvc – Assert Invoked Handler Method
• New mock-like methodCall() assertion in HandlerResultMatchers
• Assert the @Controller method invoked to handle the response
• Uses MvcUriComponentsBuilder under the hood

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

15
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&&")
.value("1234"));

16
MockRestServiceServer Improvements
• Expectations for form data in the request body
• ContentRequestMatchers.formData(MultiValueMap<String, String>)

• 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 MockRestServiceServerBuilder
• MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();

17
JUnit 5

18
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


JUnit 4 Runner API
• Very powerful

• In fact, it can do anything

• But… you can’t 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

• 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


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


Thanks!
The Kick-off Team
JUnit 5 – Roadmap
• Prototype  December 2nd, 2015

• 5.0.0-ALPHA  February 1st, 2016

• 5.0.0-M1  July 7th 2016

• 5.0.0-M2  July 23rd 2016

• M3, M4, RC1  Fall 2016

• GA  end of 2016 ... maybe


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)
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
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
• Test engine discovers and executes tests
• for a particular programming model

• Automatic registration via Java’s ServiceLoader mechanism

• JupiterTestEngine

• VintageTestEngine

• Implement your own…


T H I R D
V I N T A G E J U P I T E R
P A R T Y

P L A T F O R M
T H I R D
P A R T Y P L A T F O R M
J U P I T E R
V I N T A G E
JUnit 5 – 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
Extension APIs
• BeforeAllCallback
• BeforeEachCallback
o BeforeTestExecutionCallback

o AfterTestExecutionCallback

• AfterEachCallback
• AfterAllCallback

• ContainerExecutionCondition & TestExecutionCondition


• TestInstancePostProcessor
• ParameterResolver
• TestExecutionExceptionHandler
JUnit 5 – Programming Model
org.junit.jupiter.api

• 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
• Dynamic tests
Annotations
• @Test / @TestFactory
• @BeforeAll / @AfterAll
• @BeforeEach / @AfterEach

• @DisplayName

• @Tag

• @Disabled

• @Nested
Assertions
org.junit.jupiter.api.Assertions

• Limited set of core assertions


• assertEquals(), assertNotNull(), etc.
• assertThrows() and expectThrows()
• assertTimeout()
• assertAll()

• Supplier<String>  for lazy failure message evaluation


• message is now the last parameter

• For more power, use AssertJ, Hamcrest, etc.


Assumptions
org.junit.jupiter.api.Assumptions

• Limited set of core assumptions


• For aborting tests mid-flight

• assumeTrue() / assumeFalse()
• BooleanSupplier, Supplier<String>

• assumingThat( ? , () -> {} );
Demo
basic tests and assertions

38
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 😱
Dependency Injection
• Extension Model meets Programming Model

• ParameterResolver extension
• resolves parameters for constructors or methods

• TestInfo: inject into constructor, @Test, @BeforeEach, etc.


• access display name, tags, class, method

• TestInfoParameterResolver
• eating our own dog food ;-)

• See also:
• TestReporter
• MockitoExtension
• SpringExtension
Demo
display names and dependency injection

41
Tagging
• Declare @Tag on a test interface, class, or method

@Tag("fast")
@Test
void myFastTest() {
}
Custom Tags
• Declare @Tag as a meta-annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
@Test
public @interface FastTest {
}

@FastTest
void myFastTest() {
}
Conditional Test Execution
• Extension Model meets Programming Model

• ContainerExecutionCondition
• TestExecutionCondition

• @Disabled
• DisabledCondition
• eating our own dog food ;-)

• Deactivate via Launcher/System property


• junit.conditions.deactivate = org.junit.*
Interface Default Methods
• Introduces the concept of a test interface
• Enables multiple inheritance in tests
• a.k.a., testing traits

• @BeforeEach / @AfterEach
• @Test
• @Tag
• @ExtendWith

• See StringTests example in user guide


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


Dynamic Tests
• Conventional tests are static (i.e., known at compile time)
o @Test methods

• A DynamicTest is registered at run time


o as lambda expression in a stream, collection, etc.
o by a method annotated with @TestFactory

• Somewhat analogous to parameterized tests


Demo
dynamic tests

48
What’s Missing?
• Official IDE and build integration
• IntelliJ IDEA 2016.2: beta support
• Eclipse: on the radar, but not until 2017
• Gradle & Maven: interim solutions from JUnit Team

• Parameterized tests

• Scenario tests

• Parallel execution

• …
New in Spring Framework 5.0

50
Spring Support for JUnit 5
• Fully integrated in Spring Framework 5.0 M1
• Supports all Core Spring TestContext Framework features
• Constructor and method injection via @Autowired, @Qualifier, @Value

• Also works with Spring Framework 4.3


• https://github.com/sbrannen/spring-test-junit5

• SpringExtension
• @ExtendWith(SpringExtension.class)

• @SpringJUnitConfig and @SpringJUnitWebConfig


Demo
Spring 5 and JUnit 5

52
Spring Boot 1.4 + JUnit 5 – Custom Config
• @SpringBootTest + @AutoConfigureMockMvc +
@ExtendWith(SpringExtension.class)

@Target(TYPE)
@Retention(RUNTIME)

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = MOCK)
@AutoConfigureMockMvc
@Transactional
public @interface SpringEventsWebTest {
}
Spring Boot 1.4 + JUnit 5 – MockMvc Test
• @SpringEventsWebTest + method-level DI + MockMvc

@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))));
}
}
In closing …

55
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, spring-security, …

56
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/junit5
https://github.com/junit-team/junit5-samples

Stack Overflow
http://stackoverflow.com/tags/junit5

57
Blogs

Spring Blog
http://spring.io/blog

Swiftmind Blog
http://www.swiftmind.com/blog

58
Q&A
Sam Brannen

@Sam_Brannen @SpringCentral @JUnitTeam


slideshare.net/sbrannen spring.io junit.org/junit5

Anda mungkin juga menyukai