SlideShare una empresa de Scribd logo
1 de 103
Whitebox testing of Spring Boot applications
About myself
Application Architect @Thomas
Cook
Tech Lead - Platformers team
9+ years Java
About myself
Application Architect @Thomas
Cook
Tech Lead - Platformers team
9+ years Java
*Very happy to leave an amazing teambuilding first to make it for a 5 AM flight back to Kyiv for this presentation
What is our current mission and vision in TC?
We are developing a flexible platform that will be able to make full use of CD
practices to improve time-to-market and be resilient enough to support a variety of
new markets.
Content
1. What we do in Thomas Cook
2. What problems we are facing with testing
3. Alternative frameworks - Spock and JUnit 5
4. Spring Boot testing
Mule -> Spring Boot
Mule -> Spring Boot
TestNG + JUnit 4
Our nice little monolith
...
...
...
Well, at least it’s Spring-based!
TestNG issues
● Test class lifecycle
TestNG issues
● Test class lifecycle:
@BeforeMethod
private void beforeMethod() {
objectUnderTest = null;
MockitoAnnotations.initMocks(this);
….
}
TestNG issues
● Test class lifecycle:
@BeforeMethod
private void beforeMethod() {
objectUnderTest = null;
MockitoAnnotations.initMocks(this);
….
}
*Funnily enough you can use the same lifecycle for JUnit 5 with @TestInstance:
enum Lifecycle
PER_CLASS, PER_METHOD;
TestNG issues
● A problem with Mockito related to the way Mockito used Reflection:
https://github.com/mockito/mockito/issues/810
https://github.com/mockito/mockito/pull/948
TestNG issues
● A problem with Mockito related to the way Mockito used Reflection:
https://github.com/mockito/mockito/issues/810
https://github.com/mockito/mockito/pull/948
Issues with JUnit 4
● Not possible to have several @RunWith
Issues with JUnit 4
● Not possible to have several @RunWith
For that reason a list of custom Rules was implemented on our side:
public class MockitoRule implements MethodRule {
@Override
public Statement apply(Statement base, FrameworkMethod frameworkMethod, Object test) {
settings.test = test;
Statement wrappedStatement = new MockitoInitializationStatement(base, settings);
wrappedStatement = new MockitoVerificationStatement(wrappedStatement, settings);
return wrappedStatement;
}
What are the alternatives?
Spock: Overview
Spock: based on JUnit runner
No hassle with the runner: What’s more it extends Junit runner so it can run by
the tools you used for your tests before.
@RunWith(Sputnik.class)
public abstract class Specification extends MockingApi
….
public class Sputnik extends Runner implements Filterable, Sortable
Spock: formal semantics
JUnit tests lack formal semantics
The number one reason for using Spock is to make your tests more readable.
Spock: test blocks
Spock: test blocks
Having them in your tests is mandatory.
Otherwise a piece of code like this will not complain:
def "CreateBooking"() {
whatever
}
Spock: test example
def "should fetch Bob and Alice without errors"() {
given:
def response =
mockMvc.perform(MockMvcRequestBuilders.get("/bookings/$id")).andReturn().response
def content = new JsonSlurper().parseText(response.contentAsString)
expect:
response.status == OK.value()
and:
content.passengerName == result
where:
id || result
'5' || "Bob"
'15' || "Alice"
}
Spock: Data Pipes
Spock: Data Pipes
Can be as advances as this:
Spock: @Shared fields
Objects stored into instance fields are not shared between feature methods. Instead, every feature
method gets its own object. This helps to isolate feature methods from each other, which is often a
desirable goal.
@Shared res = new VeryExpensiveResource()
Spock: error reporting
Nice and layered: Condition not satisfied:
content.passengerName == result
| | | |
| Bob | Bob1
| false
| 1 difference (75% similarity)
| Bob(-)
| Bob(1)
Condition not satisfied:
content.passengerName == result
| | | |
| Alice | Alice2
| false
| 1 difference (83% similarity)
| Alice(-)
| Alice(2)
Spock: parameterization is way better than in JUnit 4
There is a way to do it for JUnit, but it’s an external lib. Otherwise, it’s just too
verbose
Spock: Interactions
A way to express which method invocations are expected to occur:
then: "a rejection email is sent to the customer"
0 * emailService.sendConfirmation(sampleCustomer.getEmailAddress())
1 * emailService.sendRejection(sampleCustomer.getEmailAddress())
//Can also be:
(1..3) * subscriber.receive("hello") // between one and three calls (inclusive)
(1.._) * subscriber.receive("hello") // at least one call
(_..3) * subscriber.receive("hello") // at most three calls
Spock: Interactions - powerful matchers
1 * subscriber./r.*e/("hello") // a method whose name matches the given regular expression
// (here: method name starts with 'r' and ends in 'e')
1 * subscriber.receive(_) // any single argument (including null)
1 * subscriber.receive(*_) // any argument list (including the empty argument list)
1 * _._ // any method call on any mock object
1 * _ // shortcut for and preferred over the above
Spock: Drawbacks
A bit scary versioning:
Groovy: Drawbacks
If everything inside your test/ folder will be Groovy based there’s a good
chance you will want to have some TestUtils/TestBuilders there at some
point. And you will use Groovy for all that.
Groovy: Drawbacks
Groovy: With great power...
Groovy: Drawbacks
It’s similar to java, but there will still be a learning curve and some tricky cases.
My use case - copying one object into another based on SO:
https://stackoverflow.com/questions/9072307/copy-groovy-class-properties/9072974#9072974
Groovy: Drawbacks
My use case - copying one object into another:
https://stackoverflow.com/questions/46952475/copy-object-properties-to-another-object-in-groovy
Groovy: Drawbacks
Comments/Answers:
My use case - copying one object into another:
Groovy: Drawbacks
My use case - copying one object into another:
Comments/Answers:
JUnit 5: finally released!
JUnit 5: motivation
JUnit 5: module composition
JUnit 5 is composed of several different modules from three different sub-projects.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit 5: native support in Spring 5.0
Spring-boot version 1.5.9-RELEASE is based on Spring 4 and the
SpringExtension is only available since Spring 5.
JUnit 5: can run on top of JUnit 4
JUnit 5: reason for re-architecture
● JUnit 4 test discovery and execution were tightly coupled.
● JUnit 4 - java 5 compatible - that’s ridiculous!
JUnit 5: architectural diagram
JUnit 5: all interested parties
This substantially simplifies collaboration between:
● JUnit framework developers;
● Developers writing tests for their products;
● IDE developers;
● Build tool developers.
JUnit 5: powerful ExtendWith
Only one @RunWith but many @ExtendWith.
@ExtendWith(SpringExtension.class)
JUnit 5: asserts are never skipped
Assert are not skipped if one failed:
void getBooking() throws Exception {
String bob = mockMvc.perform(MockMvcRequestBuilders.get("/bookings/5"))
.andReturn().getResponse().getContentAsString();
ObjectMapper objectMapper = new ObjectMapper();
assertAll("Analyzing Bob's record",
() -> assertEquals("NotBob", objectMapper.readValue(bob, Booking.class).getPassengerName()),
() -> assertEquals("USA", objectMapper.readValue(bob, Booking.class).getDestination()),
() -> assertEquals(Double.valueOf(35), objectMapper.readValue(bob, Booking.class).getAge()));
}
JUnit 5: asserts are never skipped
Assert are not skipped if one failed:
void getBooking() throws Exception {
String bob = mockMvc.perform(MockMvcRequestBuilders.get("/bookings/5"))
.andReturn().getResponse().getContentAsString();
ObjectMapper objectMapper = new ObjectMapper();
assertAll("Analyzing Bob's record",
() -> assertEquals("NotBob", objectMapper.readValue(bob, Booking.class).getPassengerName()),
() -> assertEquals("USA", objectMapper.readValue(bob, Booking.class).getDestination()),
() -> assertEquals(Double.valueOf(35), objectMapper.readValue(bob, Booking.class).getAge()));
}
Fail
Fail
Pass
JUnit 5: asserts are never skipped
Will require fewer iterations to stabilize your code
JUnit 5: out-of-the-box support for Exceptions
@org.junit.jupiter.api.Test
void testException() {
Executable closureContainingCodeToTest = () -> {throw new ConcurrentModificationException();};
assertThrows(ConcurrentModificationException.class, closureContainingCodeToTest);
}
JUnit 5: Autowiring into a method
@org.junit.jupiter.api.Test
void getBooking(@Autowired MockMvc mockMvc) throws Exception {
String bob = mockMvc.perform(MockMvcRequestBuilders.get("/bookings/5"))
.andReturn().getResponse().getContentAsString();
JUnit 5: Autowiring into a method
No need to create loads of fields in your test class.
Inject what is needed to a specific test method.
JUnit 5: Support for @Nested classes
@DisplayName("A stack")
class TestingAStackDemo {
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
...
}
@Nested
@DisplayName("when new")
class WhenNew {
...
}
Spring Boot Testing: Overview
Spring Boot BOM(?) specifies following test-related
dependencies:
● spring-boot-test
● spring-boot-test-autoconfigure
● spring-boot-starter-test
● solr-test-framework
● groovy-test
● groovy-testng
● hibernate-testing
● spring-batch-test
● spring-kafka-test
● spring-ldap-test
● spring-restdocs-webtestclient
● spring-ws-test
Spring Boot Testing: Overview
Spring Boot BOM(spring-boot-dependencies pom) specifies
following test-related dependencies:
● spring-boot-test
● spring-boot-test-autoconfigure
● spring-boot-starter-test
● solr-test-framework
● groovy-test
● groovy-testng
● hibernate-testing
● spring-batch-test
● spring-kafka-test
● spring-ldap-test
● spring-restdocs-webtestclient
● spring-ws-test
Spring Boot Testing: Overview
We will mainly focus on these ones:
● spring-boot-test
● spring-boot-test-autoconfigure
● spring-boot-starter-test
● solr-test-framework
● groovy-test
● groovy-testng
● hibernate-testing
● spring-batch-test
● spring-kafka-test
● spring-ldap-test
● spring-restdocs-webtestclient
● spring-ws-test
Spring Boot Testing: Overview
Only one test-specific starter:
Spring Test: Integration Testing
Spring’s integration testing support has the following primary goals:
● To manage Spring IoC container caching between test execution.
● To provide Dependency Injection of test fixture instances.
● To provide transaction management appropriate to integration testing.
● To supply Spring-specific base classes that assist developers in writing integration
tests.
Spring Test: how are transactions handled?
Your tests might run against a real database. It’s rare, but possible. We are talking
about Integration tests after all.
By default, the framework will create and roll back a transaction for each test.
If a test method deletes the contents of selected tables while running within the
transaction managed for the test, the transaction will rollback by default, and the
database will return to its state prior to execution of the test.
Spring Test: how are transactions handled?
Your tests might run against a real database. It’s rare, but possible. We are talking
about Integration tests after all.
By default, the framework will create and roll back a transaction for each test.
If a test method deletes the contents of selected tables while running within the
transaction managed for the test, the transaction will rollback by default, and the
database will return to its state prior to execution of the test.
More flexibility is available via @Commit and @Rollback
Spring Test: how are transactions handled?
Your tests might run against a real database. It’s rare, but possible. We are talking
about Integration tests after all.
By default, the framework will create and roll back a transaction for each test.
If a test method deletes the contents of selected tables while running within the
transaction managed for the test, the transaction will rollback by default, and the
database will return to its state prior to execution of the test.
Not always that straightforward. Probably depends on implicit commits and
DB engines. Will also only work for MOCK transport.
Spring Test: main actors
TestContextManager TestContext
TestExecutionListeners
Spring Test: TestContextManager
Main entry point into Spring test related functionality
Spring
Test
Context
Spring Test: factories for ExecutionListener
Spring Test: factories for ExecutionListener
Will scan your test class, look at its annotations and add its logic accordingly.
Spring Test: Reactive support
The package org.springframework.mock.http.server.reactive contains mock
implementations of ServerHttpRequest and ServerHttpResponse for use in
WebFlux applications.
The WebTestClient builds on the mock request and response to provide support
for testing WebFlux applications without an HTTP server.
Spring Test: static cache
Test suites and forked processes
The Spring TestContext framework stores application contexts in a static cache.
This means that the context is literally stored in a static variable. In other words, if
tests execute in separate processes the static cache will be cleared between each
test execution, and this will effectively disable the caching mechanism.
Spring Boot + Spock: pom file
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<configuration>
<testSources>
<testSource>
<directory>${project.basedir}/src/test/java</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</testSource>
</testSources>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compileTests</goal>
</goals>
</execution>
</executions>
</plugin>
Spring Boot + Spock: pom file
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.13</version>
</dependency>
Spring Boot + Spock: pom file
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.13</version>
</dependency>
Default scope
Spring Boot + Spock
Integration with Spock: Detached mocks via the DetachedMockFactory and
SpockMockFactoryBean classes.
class TestConfigurationForSpock {
private final detachedMockFactory = new DetachedMockFactory()
@Bean
BookingService bookingService() {
detachedMockFactory.Mock(BookingService);
}
}
Then just use: @Import(TestConfigurationForSpock)
Spring Boot + JUnit 5
Will need to include an additional library to use JUnit 5 with Spring Framework 4.3
Spring Boot + JUnit 5
There’s nothing at all Spock specific in spring-test, but you can find junit.jupiter is
there:
Spring Boot + JUnit 5
Be careful with your surefire version:
Spring Boot + JUnit 5: pom file
<dependency>
<artifactId>junit-platform-launcher</artifactId>
</dependency>
<dependency>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
<dependency>
<artifactId>junit-vintage-engine</artifactId>
</dependency>
<dependency>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency>
<artifactId>junit-jupiter-params</artifactId>
</dependency>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<includes>
<include>**/Test*.java</include>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
<include>**/*TestCase.java</include>
</includes>
</configuration>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>${junit.platform.version}</version>
</dependency>
</dependencies>
</plugin>
Spock vs JUnit 5: integration with Spring
Both frameworks provide a class with exact same name: SpringExtension.
However, the name is the only thing they have in common.
Spock vs JUnit 5: integration with Spring
SpringExtension
Spock JUnit 5
Tries to find any Spring-specific annotation on a test
class(spec): ContentHierarchy, BootstrapWith,
ContextConfiguration.
Using Spring-provided MetaAnnotaionUtils, so that it
can traverse class hierarchy.
Spring Test SpringExtention implements all possible
JUnit 5 callbacks(.e.g.: BeforeAllCallback,
AfterAllCallback)
If found, creates a TestContextManager and
delegate to it.
Will either get TestContextManager from a store of
create one.
Attaches Spock-specific listener for managing
Mocks:
testContext.setAttribute(MOCKED_BEANS_LIST,
mockedBeans);
Will wrap TestContextManager calls and delegate to
it. E.g.:
public void beforeAll(ExtensionContext context) {
getTestContextManager(context).beforeTestClass();
Spring Boot: autoconfigure slicing
Auto-configured tests
The spring-boot-test-autoconfigure module includes a number of annotations that can be used to
automatically configure different ‘slices’ of your app for testing purposes.
Examples:
● @WebMvcTest
● @JsonTest
● @DataJpaTest
● @JdbcTest
● @DataMongoTest
● ...
Spring Boot: autoconfigure slicing
@*Test would normally contain several @AutoConfigure* annotations:
For example:
...
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager
@ImportAutoConfiguration
public @interface DataJpaTest
Spring Boot: autoconfigure slicing
To tweak @*Test mechanism, you can use a corresponding @AutoConfigure*
annotation.
For example:
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
public class ExampleRepositoryTests {
// ...
}
Spring Boot: autoconfigure slicing
Have you noticed this relatively unremarkable meta annotation:
@OverrideAutoConfiguration(enabled = false)
It will effectively set:
spring.boot.enableautoconfiguration=false
via AbstractTestContextBootstrapper
String Boot: Bootstrapping
@BootstrapWith is used on @SpringBootTest, for example.
String Boot: Bootstrapping
@BootstrapWith is used on @SpringBootTest, for example.
● Aware of Spring Boot
application structure;
● Helps SpringBootTest;
String Boot: Bootstrapping
As TestContextManager is the main entry point for test frameworks all they need
is to create one:
public TestContextManager(Class<?> testClass) {
this(BootstrapUtils.resolveTestContextBootstrapper(BootstrapUtils.createBootstrapContext(testClass)));
}
Spring Boot: Slicing
Do not litter the application’s main class with configuration settings that are are
specific to a particular area of its functionality.
Extract them into specific @Configuration instead. Otherwise they will be picked
up by all slice tests, which might not be what you want:
@SpringBootApplication
@EnableBatchProcessing - DO NOT DO IT THIS WAY
public class SampleApplication { ... }
Spring Boot: Custom component scanning
Another source of confusion is classpath scanning. Assume that, while you
structured your code in a sensible way, you need to scan an additional package.
Your application may resemble the following code:
@SpringBootApplication
@ComponentScan({ "com.example.app", "org.acme.another" }) - ALSO BAD
public class SampleApplication { ... }
This effectively overrides the default component scan directive with the side effect
of scanning those two packages regardless of the slice that you’ve chosen.
Spring Boot: TypeExcludeFilter
AutoConfigurationExcludeFilter - tells Spring Boot to exclude scanning
autoconfigurations. To use SpringFactoriesLoader instead.
TypeExcludeFilter - is an interesting case. While it’s in spring-boot jar, the doc
actually says: primarily used internally to support spring-boot-test.
Spring Boot: TypeExcludeFilter
Pivotal cares about your application’s tests so much, they put a test-specific
logic into their main Spring Boot module!
Spring Boot: TypeExcludeFilter
Indeed, all subclasses seem to be coming from spring-boot-test-autoconfigure and
spring-boot-test:
Spring Boot: TypeExcludeFilter
What a specific test filter effectively does is:
1. Loads a corresponding annotation. E.g.: WebMvcTest for
WebMvcTypeExcludeFilter, DataJpaTest for DataJpaTypeExcludeFilter;
2. Inside *ExcludeFilter add specific annotations for which you want to enable
ComponentScan. For most *ExcludeFilters it is not required, however. They
will simply rely on SpringFactoriesLoader
@TestConfiguration :
● Unlike a nested @Configuration class which would be used instead of a your
application’s primary configuration, a nested @TestConfiguration class will
be used in addition to your application’s primary configuration;
● When placed on a top-level class, @TestConfiguration indicates that classes
in src/test/java should not be picked up by scanning. Use explicit @Import to
use them.
Spring Boot: overriding configurations
Spring Boot: Mocking and spying beans
For example, you may have a facade over some remote service that’s unavailable
during development.
Spring Boot includes a @MockBean annotation that can be used to define a
Mockito mock for a bean inside your ApplicationContext.
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
@MockBean
private RemoteService remoteService;
Spring Boot: AutoConfigureMockMvc
There is an option to not start the server at all, but test only the layer below that,
where Spring handles the incoming HTTP request and hands it off to your
controller. That way, almost the full stack is used, and your code will be called
exactly the same way as if it was processing a real HTTP request, but without the
cost of starting the server. To do that we will use Spring’s MockMvc, and we can
ask for that to be injected for us by using the @AutoConfigureMockMvc annotation
on the test case.
https://spring.io/guides/gs/testing-web/
Spring Boot: WebMvcTest
@WebMvcTest
Only web layer is instantiated, not the whole context.
Often @WebMvcTest will be limited to a single controller and used in combination
with @MockBean to provide mock implementations for required collaborators.
Spring Boot: WebMvcTest vs AutoConfigureMockMvc vs
SpringBootTest
The main difference is inside META-INF/spring.factories:
# AutoConfigureMockMvc auto-configuration imports
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc=
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration,
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration,
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration,
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration
You’ll notice that WebMvcTest has also a @ImportAutoConfiguration *, but there’s
no entry in spring.factories for it.
https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4
Spring Boot: WebMvcTest vs AutoConfigureMockMvc vs
SpringBootTest
The main difference is inside META-INF/spring.factories:
# AutoConfigureMockMvc auto-configuration imports
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc=
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration,
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration,
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration,
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration
You’ll notice that WebMvcTest has also a @ImportAutoConfiguration *, but there’s
no entry in spring.factories for it.
However it has an exclude filter to reduce the amount of scanned objects.
Spring Boot: SpringBootTest MOCK WebEnvironment
Embedded servlet containers are not started when using this attribute. Can be
used in conjunction with @AutoConfigureMockMvc for MockMvc-based testing of
your application.
Spring Boot: SpringBootTest
RANDOM_PORT/DEFINED_PORT WebEnvironment
A test like this will run perfectly fine with real HTTP transport:
@SpringBootTest(classes = RamlBasedProducerApplication, webEnvironment =
SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@OverrideAutoConfiguration(enabled = true)
class BookingServiceImplSpockTest extends Specification {
@LocalServerPort
private int port;
@Autowired
MockMvc mockMvc;
Spring will inject different ServletContexts into MockMvc depending on webEnv.
Spring Boot: Test utilities
● EnvironmentTestUtils(addEnvironment(env, "org=Spring", "name=Boot"))
● TestRestTemplate(behave in a test-friendly way by not throwing exceptions
on server-side errors)
● MockRestServiceServer(part of Spring Test)
Whitebox testing of Spring Boot applications

Más contenido relacionado

La actualidad más candente

Authentication
AuthenticationAuthentication
Authentication
soon
 

La actualidad más candente (20)

Authentication
AuthenticationAuthentication
Authentication
 
API Asynchrones en Java 8
API Asynchrones en Java 8API Asynchrones en Java 8
API Asynchrones en Java 8
 
Angular 2
Angular 2Angular 2
Angular 2
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
Django Architecture Introduction
Django Architecture IntroductionDjango Architecture Introduction
Django Architecture Introduction
 
Spring Core
Spring CoreSpring Core
Spring Core
 
Spring Data JPA
Spring Data JPASpring Data JPA
Spring Data JPA
 
Introducing type script
Introducing type scriptIntroducing type script
Introducing type script
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Java 8 features
Java 8 featuresJava 8 features
Java 8 features
 
An Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
An Introduction to JUnit 5 and how to use it with Spring boot tests and MockitoAn Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
An Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
 
Jpa
JpaJpa
Jpa
 
java 8 new features
java 8 new features java 8 new features
java 8 new features
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js Express
 
JUnit & Mockito, first steps
JUnit & Mockito, first stepsJUnit & Mockito, first steps
JUnit & Mockito, first steps
 
Java 8 - Features Overview
Java 8 - Features OverviewJava 8 - Features Overview
Java 8 - Features Overview
 
Java 8 lambda
Java 8 lambdaJava 8 lambda
Java 8 lambda
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
Better APIs with GraphQL
Better APIs with GraphQL Better APIs with GraphQL
Better APIs with GraphQL
 
API Testing
API TestingAPI Testing
API Testing
 

Similar a Whitebox testing of Spring Boot applications

JavaProgrammingForBeginners-Presentation.pdf
JavaProgrammingForBeginners-Presentation.pdfJavaProgrammingForBeginners-Presentation.pdf
JavaProgrammingForBeginners-Presentation.pdf
Sathwika7
 
GeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingGeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testing
Jakub Marchwicki
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
James Williams
 

Similar a Whitebox testing of Spring Boot applications (20)

Testing Spring Boot application in post-JUnit 4 world
Testing Spring Boot application in post-JUnit 4 worldTesting Spring Boot application in post-JUnit 4 world
Testing Spring Boot application in post-JUnit 4 world
 
Unit testing with Spock Framework
Unit testing with Spock FrameworkUnit testing with Spock Framework
Unit testing with Spock Framework
 
Cool JVM Tools to Help You Test
Cool JVM Tools to Help You TestCool JVM Tools to Help You Test
Cool JVM Tools to Help You Test
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
Unit Testing in iOS
Unit Testing in iOSUnit Testing in iOS
Unit Testing in iOS
 
RoboSpock Poznań ADG 2016
RoboSpock Poznań ADG 2016RoboSpock Poznań ADG 2016
RoboSpock Poznań ADG 2016
 
RoboSpock
RoboSpockRoboSpock
RoboSpock
 
Spock
SpockSpock
Spock
 
Using the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM DevelopmentUsing the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM Development
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 
Google mock training
Google mock trainingGoogle mock training
Google mock training
 
Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMock
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
 
JavaProgrammingForBeginners-Presentation.pdf
JavaProgrammingForBeginners-Presentation.pdfJavaProgrammingForBeginners-Presentation.pdf
JavaProgrammingForBeginners-Presentation.pdf
 
An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java Developers
 
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
North Virginia Coldfusion User Group Meetup - Testbox - July 19th 2017
 
GeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingGeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testing
 
JavaScript Miller Columns
JavaScript Miller ColumnsJavaScript Miller Columns
JavaScript Miller Columns
 
Greach 2015 Spock workshop
Greach 2015 Spock workshopGreach 2015 Spock workshop
Greach 2015 Spock workshop
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
 

Último

%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 

Último (20)

%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 

Whitebox testing of Spring Boot applications

  • 1. Whitebox testing of Spring Boot applications
  • 2. About myself Application Architect @Thomas Cook Tech Lead - Platformers team 9+ years Java
  • 3. About myself Application Architect @Thomas Cook Tech Lead - Platformers team 9+ years Java *Very happy to leave an amazing teambuilding first to make it for a 5 AM flight back to Kyiv for this presentation
  • 4. What is our current mission and vision in TC? We are developing a flexible platform that will be able to make full use of CD practices to improve time-to-market and be resilient enough to support a variety of new markets.
  • 5. Content 1. What we do in Thomas Cook 2. What problems we are facing with testing 3. Alternative frameworks - Spock and JUnit 5 4. Spring Boot testing
  • 7. Mule -> Spring Boot TestNG + JUnit 4
  • 8. Our nice little monolith
  • 9. ...
  • 10. ...
  • 11. ...
  • 12. Well, at least it’s Spring-based!
  • 13. TestNG issues ● Test class lifecycle
  • 14. TestNG issues ● Test class lifecycle: @BeforeMethod private void beforeMethod() { objectUnderTest = null; MockitoAnnotations.initMocks(this); …. }
  • 15. TestNG issues ● Test class lifecycle: @BeforeMethod private void beforeMethod() { objectUnderTest = null; MockitoAnnotations.initMocks(this); …. } *Funnily enough you can use the same lifecycle for JUnit 5 with @TestInstance: enum Lifecycle PER_CLASS, PER_METHOD;
  • 16. TestNG issues ● A problem with Mockito related to the way Mockito used Reflection: https://github.com/mockito/mockito/issues/810 https://github.com/mockito/mockito/pull/948
  • 17. TestNG issues ● A problem with Mockito related to the way Mockito used Reflection: https://github.com/mockito/mockito/issues/810 https://github.com/mockito/mockito/pull/948
  • 18. Issues with JUnit 4 ● Not possible to have several @RunWith
  • 19. Issues with JUnit 4 ● Not possible to have several @RunWith For that reason a list of custom Rules was implemented on our side: public class MockitoRule implements MethodRule { @Override public Statement apply(Statement base, FrameworkMethod frameworkMethod, Object test) { settings.test = test; Statement wrappedStatement = new MockitoInitializationStatement(base, settings); wrappedStatement = new MockitoVerificationStatement(wrappedStatement, settings); return wrappedStatement; }
  • 20. What are the alternatives?
  • 22. Spock: based on JUnit runner No hassle with the runner: What’s more it extends Junit runner so it can run by the tools you used for your tests before. @RunWith(Sputnik.class) public abstract class Specification extends MockingApi …. public class Sputnik extends Runner implements Filterable, Sortable
  • 23. Spock: formal semantics JUnit tests lack formal semantics The number one reason for using Spock is to make your tests more readable.
  • 25. Spock: test blocks Having them in your tests is mandatory. Otherwise a piece of code like this will not complain: def "CreateBooking"() { whatever }
  • 26. Spock: test example def "should fetch Bob and Alice without errors"() { given: def response = mockMvc.perform(MockMvcRequestBuilders.get("/bookings/$id")).andReturn().response def content = new JsonSlurper().parseText(response.contentAsString) expect: response.status == OK.value() and: content.passengerName == result where: id || result '5' || "Bob" '15' || "Alice" }
  • 28. Spock: Data Pipes Can be as advances as this:
  • 29. Spock: @Shared fields Objects stored into instance fields are not shared between feature methods. Instead, every feature method gets its own object. This helps to isolate feature methods from each other, which is often a desirable goal. @Shared res = new VeryExpensiveResource()
  • 30. Spock: error reporting Nice and layered: Condition not satisfied: content.passengerName == result | | | | | Bob | Bob1 | false | 1 difference (75% similarity) | Bob(-) | Bob(1) Condition not satisfied: content.passengerName == result | | | | | Alice | Alice2 | false | 1 difference (83% similarity) | Alice(-) | Alice(2)
  • 31. Spock: parameterization is way better than in JUnit 4 There is a way to do it for JUnit, but it’s an external lib. Otherwise, it’s just too verbose
  • 32. Spock: Interactions A way to express which method invocations are expected to occur: then: "a rejection email is sent to the customer" 0 * emailService.sendConfirmation(sampleCustomer.getEmailAddress()) 1 * emailService.sendRejection(sampleCustomer.getEmailAddress()) //Can also be: (1..3) * subscriber.receive("hello") // between one and three calls (inclusive) (1.._) * subscriber.receive("hello") // at least one call (_..3) * subscriber.receive("hello") // at most three calls
  • 33. Spock: Interactions - powerful matchers 1 * subscriber./r.*e/("hello") // a method whose name matches the given regular expression // (here: method name starts with 'r' and ends in 'e') 1 * subscriber.receive(_) // any single argument (including null) 1 * subscriber.receive(*_) // any argument list (including the empty argument list) 1 * _._ // any method call on any mock object 1 * _ // shortcut for and preferred over the above
  • 34. Spock: Drawbacks A bit scary versioning:
  • 35. Groovy: Drawbacks If everything inside your test/ folder will be Groovy based there’s a good chance you will want to have some TestUtils/TestBuilders there at some point. And you will use Groovy for all that.
  • 37. Groovy: Drawbacks It’s similar to java, but there will still be a learning curve and some tricky cases. My use case - copying one object into another based on SO: https://stackoverflow.com/questions/9072307/copy-groovy-class-properties/9072974#9072974
  • 38. Groovy: Drawbacks My use case - copying one object into another: https://stackoverflow.com/questions/46952475/copy-object-properties-to-another-object-in-groovy
  • 39. Groovy: Drawbacks Comments/Answers: My use case - copying one object into another:
  • 40. Groovy: Drawbacks My use case - copying one object into another: Comments/Answers:
  • 41. JUnit 5: finally released!
  • 43. JUnit 5: module composition JUnit 5 is composed of several different modules from three different sub-projects. JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
  • 44. JUnit 5: native support in Spring 5.0 Spring-boot version 1.5.9-RELEASE is based on Spring 4 and the SpringExtension is only available since Spring 5.
  • 45. JUnit 5: can run on top of JUnit 4
  • 46. JUnit 5: reason for re-architecture ● JUnit 4 test discovery and execution were tightly coupled. ● JUnit 4 - java 5 compatible - that’s ridiculous!
  • 48. JUnit 5: all interested parties This substantially simplifies collaboration between: ● JUnit framework developers; ● Developers writing tests for their products; ● IDE developers; ● Build tool developers.
  • 49. JUnit 5: powerful ExtendWith Only one @RunWith but many @ExtendWith. @ExtendWith(SpringExtension.class)
  • 50. JUnit 5: asserts are never skipped Assert are not skipped if one failed: void getBooking() throws Exception { String bob = mockMvc.perform(MockMvcRequestBuilders.get("/bookings/5")) .andReturn().getResponse().getContentAsString(); ObjectMapper objectMapper = new ObjectMapper(); assertAll("Analyzing Bob's record", () -> assertEquals("NotBob", objectMapper.readValue(bob, Booking.class).getPassengerName()), () -> assertEquals("USA", objectMapper.readValue(bob, Booking.class).getDestination()), () -> assertEquals(Double.valueOf(35), objectMapper.readValue(bob, Booking.class).getAge())); }
  • 51. JUnit 5: asserts are never skipped Assert are not skipped if one failed: void getBooking() throws Exception { String bob = mockMvc.perform(MockMvcRequestBuilders.get("/bookings/5")) .andReturn().getResponse().getContentAsString(); ObjectMapper objectMapper = new ObjectMapper(); assertAll("Analyzing Bob's record", () -> assertEquals("NotBob", objectMapper.readValue(bob, Booking.class).getPassengerName()), () -> assertEquals("USA", objectMapper.readValue(bob, Booking.class).getDestination()), () -> assertEquals(Double.valueOf(35), objectMapper.readValue(bob, Booking.class).getAge())); } Fail Fail Pass
  • 52. JUnit 5: asserts are never skipped Will require fewer iterations to stabilize your code
  • 53. JUnit 5: out-of-the-box support for Exceptions @org.junit.jupiter.api.Test void testException() { Executable closureContainingCodeToTest = () -> {throw new ConcurrentModificationException();}; assertThrows(ConcurrentModificationException.class, closureContainingCodeToTest); }
  • 54. JUnit 5: Autowiring into a method @org.junit.jupiter.api.Test void getBooking(@Autowired MockMvc mockMvc) throws Exception { String bob = mockMvc.perform(MockMvcRequestBuilders.get("/bookings/5")) .andReturn().getResponse().getContentAsString();
  • 55. JUnit 5: Autowiring into a method No need to create loads of fields in your test class. Inject what is needed to a specific test method.
  • 56. JUnit 5: Support for @Nested classes @DisplayName("A stack") class TestingAStackDemo { @Test @DisplayName("is instantiated with new Stack()") void isInstantiatedWithNew() { ... } @Nested @DisplayName("when new") class WhenNew { ... }
  • 57. Spring Boot Testing: Overview Spring Boot BOM(?) specifies following test-related dependencies: ● spring-boot-test ● spring-boot-test-autoconfigure ● spring-boot-starter-test ● solr-test-framework ● groovy-test ● groovy-testng ● hibernate-testing ● spring-batch-test ● spring-kafka-test ● spring-ldap-test ● spring-restdocs-webtestclient ● spring-ws-test
  • 58. Spring Boot Testing: Overview Spring Boot BOM(spring-boot-dependencies pom) specifies following test-related dependencies: ● spring-boot-test ● spring-boot-test-autoconfigure ● spring-boot-starter-test ● solr-test-framework ● groovy-test ● groovy-testng ● hibernate-testing ● spring-batch-test ● spring-kafka-test ● spring-ldap-test ● spring-restdocs-webtestclient ● spring-ws-test
  • 59. Spring Boot Testing: Overview We will mainly focus on these ones: ● spring-boot-test ● spring-boot-test-autoconfigure ● spring-boot-starter-test ● solr-test-framework ● groovy-test ● groovy-testng ● hibernate-testing ● spring-batch-test ● spring-kafka-test ● spring-ldap-test ● spring-restdocs-webtestclient ● spring-ws-test
  • 60. Spring Boot Testing: Overview Only one test-specific starter:
  • 61. Spring Test: Integration Testing Spring’s integration testing support has the following primary goals: ● To manage Spring IoC container caching between test execution. ● To provide Dependency Injection of test fixture instances. ● To provide transaction management appropriate to integration testing. ● To supply Spring-specific base classes that assist developers in writing integration tests.
  • 62. Spring Test: how are transactions handled? Your tests might run against a real database. It’s rare, but possible. We are talking about Integration tests after all. By default, the framework will create and roll back a transaction for each test. If a test method deletes the contents of selected tables while running within the transaction managed for the test, the transaction will rollback by default, and the database will return to its state prior to execution of the test.
  • 63. Spring Test: how are transactions handled? Your tests might run against a real database. It’s rare, but possible. We are talking about Integration tests after all. By default, the framework will create and roll back a transaction for each test. If a test method deletes the contents of selected tables while running within the transaction managed for the test, the transaction will rollback by default, and the database will return to its state prior to execution of the test. More flexibility is available via @Commit and @Rollback
  • 64. Spring Test: how are transactions handled? Your tests might run against a real database. It’s rare, but possible. We are talking about Integration tests after all. By default, the framework will create and roll back a transaction for each test. If a test method deletes the contents of selected tables while running within the transaction managed for the test, the transaction will rollback by default, and the database will return to its state prior to execution of the test. Not always that straightforward. Probably depends on implicit commits and DB engines. Will also only work for MOCK transport.
  • 65. Spring Test: main actors TestContextManager TestContext TestExecutionListeners
  • 66. Spring Test: TestContextManager Main entry point into Spring test related functionality Spring Test Context
  • 67. Spring Test: factories for ExecutionListener
  • 68. Spring Test: factories for ExecutionListener Will scan your test class, look at its annotations and add its logic accordingly.
  • 69. Spring Test: Reactive support The package org.springframework.mock.http.server.reactive contains mock implementations of ServerHttpRequest and ServerHttpResponse for use in WebFlux applications. The WebTestClient builds on the mock request and response to provide support for testing WebFlux applications without an HTTP server.
  • 70. Spring Test: static cache Test suites and forked processes The Spring TestContext framework stores application contexts in a static cache. This means that the context is literally stored in a static variable. In other words, if tests execute in separate processes the static cache will be cleared between each test execution, and this will effectively disable the caching mechanism.
  • 71. Spring Boot + Spock: pom file <plugin> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> <configuration> <testSources> <testSource> <directory>${project.basedir}/src/test/java</directory> <includes> <include>**/*.groovy</include> </includes> </testSource> </testSources> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compileTests</goal> </goals> </execution> </executions> </plugin>
  • 72. Spring Boot + Spock: pom file <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-core</artifactId> <version>1.1-groovy-2.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-spring</artifactId> <version>1.1-groovy-2.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.4.13</version> </dependency>
  • 73. Spring Boot + Spock: pom file <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-core</artifactId> <version>1.1-groovy-2.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-spring</artifactId> <version>1.1-groovy-2.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.4.13</version> </dependency> Default scope
  • 74. Spring Boot + Spock Integration with Spock: Detached mocks via the DetachedMockFactory and SpockMockFactoryBean classes. class TestConfigurationForSpock { private final detachedMockFactory = new DetachedMockFactory() @Bean BookingService bookingService() { detachedMockFactory.Mock(BookingService); } } Then just use: @Import(TestConfigurationForSpock)
  • 75. Spring Boot + JUnit 5 Will need to include an additional library to use JUnit 5 with Spring Framework 4.3
  • 76. Spring Boot + JUnit 5 There’s nothing at all Spock specific in spring-test, but you can find junit.jupiter is there:
  • 77. Spring Boot + JUnit 5 Be careful with your surefire version:
  • 78. Spring Boot + JUnit 5: pom file <dependency> <artifactId>junit-platform-launcher</artifactId> </dependency> <dependency> <artifactId>junit-jupiter-engine</artifactId> </dependency> <dependency> <artifactId>junit-vintage-engine</artifactId> </dependency> <dependency> <artifactId>junit-jupiter-api</artifactId> </dependency> <dependency> <artifactId>junit-jupiter-params</artifactId> </dependency> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> <configuration> <includes> <include>**/Test*.java</include> <include>**/*Test.java</include> <include>**/*Tests.java</include> <include>**/*TestCase.java</include> </includes> </configuration> <dependencies> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-surefire-provider</artifactId> <version>${junit.platform.version}</version> </dependency> </dependencies> </plugin>
  • 79. Spock vs JUnit 5: integration with Spring Both frameworks provide a class with exact same name: SpringExtension. However, the name is the only thing they have in common.
  • 80. Spock vs JUnit 5: integration with Spring SpringExtension Spock JUnit 5 Tries to find any Spring-specific annotation on a test class(spec): ContentHierarchy, BootstrapWith, ContextConfiguration. Using Spring-provided MetaAnnotaionUtils, so that it can traverse class hierarchy. Spring Test SpringExtention implements all possible JUnit 5 callbacks(.e.g.: BeforeAllCallback, AfterAllCallback) If found, creates a TestContextManager and delegate to it. Will either get TestContextManager from a store of create one. Attaches Spock-specific listener for managing Mocks: testContext.setAttribute(MOCKED_BEANS_LIST, mockedBeans); Will wrap TestContextManager calls and delegate to it. E.g.: public void beforeAll(ExtensionContext context) { getTestContextManager(context).beforeTestClass();
  • 81. Spring Boot: autoconfigure slicing Auto-configured tests The spring-boot-test-autoconfigure module includes a number of annotations that can be used to automatically configure different ‘slices’ of your app for testing purposes. Examples: ● @WebMvcTest ● @JsonTest ● @DataJpaTest ● @JdbcTest ● @DataMongoTest ● ...
  • 82. Spring Boot: autoconfigure slicing @*Test would normally contain several @AutoConfigure* annotations: For example: ... @BootstrapWith(SpringBootTestContextBootstrapper.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataJpaTypeExcludeFilter.class) @Transactional @AutoConfigureCache @AutoConfigureDataJpa @AutoConfigureTestDatabase @AutoConfigureTestEntityManager @ImportAutoConfiguration public @interface DataJpaTest
  • 83. Spring Boot: autoconfigure slicing To tweak @*Test mechanism, you can use a corresponding @AutoConfigure* annotation. For example: @RunWith(SpringRunner.class) @DataJpaTest @AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE) public class ExampleRepositoryTests { // ... }
  • 84. Spring Boot: autoconfigure slicing Have you noticed this relatively unremarkable meta annotation: @OverrideAutoConfiguration(enabled = false) It will effectively set: spring.boot.enableautoconfiguration=false via AbstractTestContextBootstrapper
  • 85. String Boot: Bootstrapping @BootstrapWith is used on @SpringBootTest, for example.
  • 86. String Boot: Bootstrapping @BootstrapWith is used on @SpringBootTest, for example. ● Aware of Spring Boot application structure; ● Helps SpringBootTest;
  • 87. String Boot: Bootstrapping As TestContextManager is the main entry point for test frameworks all they need is to create one: public TestContextManager(Class<?> testClass) { this(BootstrapUtils.resolveTestContextBootstrapper(BootstrapUtils.createBootstrapContext(testClass))); }
  • 88. Spring Boot: Slicing Do not litter the application’s main class with configuration settings that are are specific to a particular area of its functionality. Extract them into specific @Configuration instead. Otherwise they will be picked up by all slice tests, which might not be what you want: @SpringBootApplication @EnableBatchProcessing - DO NOT DO IT THIS WAY public class SampleApplication { ... }
  • 89. Spring Boot: Custom component scanning Another source of confusion is classpath scanning. Assume that, while you structured your code in a sensible way, you need to scan an additional package. Your application may resemble the following code: @SpringBootApplication @ComponentScan({ "com.example.app", "org.acme.another" }) - ALSO BAD public class SampleApplication { ... } This effectively overrides the default component scan directive with the side effect of scanning those two packages regardless of the slice that you’ve chosen.
  • 90. Spring Boot: TypeExcludeFilter AutoConfigurationExcludeFilter - tells Spring Boot to exclude scanning autoconfigurations. To use SpringFactoriesLoader instead. TypeExcludeFilter - is an interesting case. While it’s in spring-boot jar, the doc actually says: primarily used internally to support spring-boot-test.
  • 91. Spring Boot: TypeExcludeFilter Pivotal cares about your application’s tests so much, they put a test-specific logic into their main Spring Boot module!
  • 92. Spring Boot: TypeExcludeFilter Indeed, all subclasses seem to be coming from spring-boot-test-autoconfigure and spring-boot-test:
  • 93. Spring Boot: TypeExcludeFilter What a specific test filter effectively does is: 1. Loads a corresponding annotation. E.g.: WebMvcTest for WebMvcTypeExcludeFilter, DataJpaTest for DataJpaTypeExcludeFilter; 2. Inside *ExcludeFilter add specific annotations for which you want to enable ComponentScan. For most *ExcludeFilters it is not required, however. They will simply rely on SpringFactoriesLoader
  • 94. @TestConfiguration : ● Unlike a nested @Configuration class which would be used instead of a your application’s primary configuration, a nested @TestConfiguration class will be used in addition to your application’s primary configuration; ● When placed on a top-level class, @TestConfiguration indicates that classes in src/test/java should not be picked up by scanning. Use explicit @Import to use them. Spring Boot: overriding configurations
  • 95. Spring Boot: Mocking and spying beans For example, you may have a facade over some remote service that’s unavailable during development. Spring Boot includes a @MockBean annotation that can be used to define a Mockito mock for a bean inside your ApplicationContext. @RunWith(SpringRunner.class) @SpringBootTest public class MyTests { @MockBean private RemoteService remoteService;
  • 96. Spring Boot: AutoConfigureMockMvc There is an option to not start the server at all, but test only the layer below that, where Spring handles the incoming HTTP request and hands it off to your controller. That way, almost the full stack is used, and your code will be called exactly the same way as if it was processing a real HTTP request, but without the cost of starting the server. To do that we will use Spring’s MockMvc, and we can ask for that to be injected for us by using the @AutoConfigureMockMvc annotation on the test case. https://spring.io/guides/gs/testing-web/
  • 97. Spring Boot: WebMvcTest @WebMvcTest Only web layer is instantiated, not the whole context. Often @WebMvcTest will be limited to a single controller and used in combination with @MockBean to provide mock implementations for required collaborators.
  • 98. Spring Boot: WebMvcTest vs AutoConfigureMockMvc vs SpringBootTest The main difference is inside META-INF/spring.factories: # AutoConfigureMockMvc auto-configuration imports org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc= org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration You’ll notice that WebMvcTest has also a @ImportAutoConfiguration *, but there’s no entry in spring.factories for it. https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4
  • 99. Spring Boot: WebMvcTest vs AutoConfigureMockMvc vs SpringBootTest The main difference is inside META-INF/spring.factories: # AutoConfigureMockMvc auto-configuration imports org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc= org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration You’ll notice that WebMvcTest has also a @ImportAutoConfiguration *, but there’s no entry in spring.factories for it. However it has an exclude filter to reduce the amount of scanned objects.
  • 100. Spring Boot: SpringBootTest MOCK WebEnvironment Embedded servlet containers are not started when using this attribute. Can be used in conjunction with @AutoConfigureMockMvc for MockMvc-based testing of your application.
  • 101. Spring Boot: SpringBootTest RANDOM_PORT/DEFINED_PORT WebEnvironment A test like this will run perfectly fine with real HTTP transport: @SpringBootTest(classes = RamlBasedProducerApplication, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc @OverrideAutoConfiguration(enabled = true) class BookingServiceImplSpockTest extends Specification { @LocalServerPort private int port; @Autowired MockMvc mockMvc; Spring will inject different ServletContexts into MockMvc depending on webEnv.
  • 102. Spring Boot: Test utilities ● EnvironmentTestUtils(addEnvironment(env, "org=Spring", "name=Boot")) ● TestRestTemplate(behave in a test-friendly way by not throwing exceptions on server-side errors) ● MockRestServiceServer(part of Spring Test)

Notas del editor

  1. Mention Spring Boot logo and “whatever”
  2. https://gist.github.com/jeffsheets/ada3de8fe4a536e5351b
  3. Can also be a multi-variable data pipe(a list from the left hand side)
  4. Can also be a multi-variable data pipe(a list from the left hand side)
  5. @Unroll - another cool feature.
  6. https://gist.github.com/jeffsheets/ada3de8fe4a536e5351b
  7. http://jakubdziworski.github.io/java/groovy/spock/2016/05/14/spock-cheatsheet.html
  8. Spock - no official logo. WTF?
  9. If they say it’s a ball of mud, it’s probably so.
  10. https://www.youtube.com/watch?v=oGaatK5ShUs
  11. http://mvpjava.com/spring-boot-junit5/ https://www.youtube.com/watch?time_continue=9&v=K60vyIHAUOQ
  12. If you want a transaction to commit — unusual, but occasionally useful when you want a particular test to populate or modify the database — the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the@Commit annotation.
  13. If you want a transaction to commit — unusual, but occasionally useful when you want a particular test to populate or modify the database — the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the@Commit annotation.
  14. If you want a transaction to commit — unusual, but occasionally useful when you want a particular test to populate or modify the database — the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the@Commit annotation.
  15. If you want a transaction to commit — unusual, but occasionally useful when you want a particular test to populate or modify the database — the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the@Commit annotation.
  16. If you want a transaction to commit — unusual, but occasionally useful when you want a particular test to populate or modify the database — the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the@Commit annotation.
  17. Talk about TestContextmanager and TestContext
  18. Talk about TestContextmanager and TestContext
  19. All test scope
  20. public TestContextManager(Class<?> testClass) { this(BootstrapUtils.resolveTestContextBootstrapper(BootstrapUtils.createBootstrapContext(testClass))); }
  21. public TestContextManager(Class<?> testClass) { this(BootstrapUtils.resolveTestContextBootstrapper(BootstrapUtils.createBootstrapContext(testClass))); }
  22. Several at once can cauae problems.
  23. https://spring.io/guides/gs/testing-web/
  24. https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4
  25. https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4