Introduction
Spring Boot test slices are a great way to test your services with Spring Boot beans and configuration. They will load only a necessary part of framework for you and thus making integration tests:
- faster,
- easier to reason about,
- and less fragile (as they will not break on changes in unrelated configuration / beans).
Some time back I've written an article about making DataJpaTest to catch more bugs but let's have a look now at some general tips on using all types of slices:
Tip 1: How to resolve dependencies of a tested service
Many times a test with a slice will need additional dependencies. There are a few ways how to load them to the test context:
@MockBean
- creates a mockito instance for annotated field. Do not confuse this annotation with@Mock
from Mockito library.@Import
- loads a service/configuration into the test context.@AutoConfigure*
annotations - autoconfigures more beans from SpringBoot application; for example@AutoConfigureJson
will configure Jackson's ObjectMapper. - You should have only one slice annotation on a test class but you can add more autoconfigurations if necessary.
Let's have a look at an example with a CreateUserService
depending on JPA repositories, Jackson ObjectMapper and some custom classes for generating passwords / sending emails:
@DataJpaTest
@AutoConfigureJson
@Import({
CreateUserService.class,
RandomPasswordGenerator.class
})
class CreateUserServiceTest {
@MockBean
private EmailSender emailSender;
@Autowired
private CreateUserService createUserService;
// ...
}
Tip 2: Make sure SpringBootApplication does not have unnecessary configuration
Your main application class should ideally look like this:
@SpringBootApplication(
exclude = {/* any autoconfiguration you want to disable */}
)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Any additional configuration would be loaded by all slices too and so it should go to separate code>@Configuration classes if possible. (See docs for configuration and slices.)
Tip 3: You can extend existing slices
Do you need additional beans for every single WebMvcTest
(or any other test slice)? Simply extend the existing slice and import/mock your dependencies:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@WebMvcTest
@Import(MandatoryDependency.class)
public @interface CustomWebMvcTest {
@AliasFor(annotation = WebMvcTest.class, attribute = "controllers")
Class<?>[] controllers() default {};
}
Notice that you can also "forward" fields of the new slice to the original slice using code>@AliasFor annotation.
Final thoughts
I guess this goes without saying - but checking documentation, or implementation of slices can show you even more possibilities. For example DataJpaTest
automatically configures TestEntityManager
, WebMvcTest
can load only one controller using controllers
attribute, JsonTest
provides JacksonTester
class for easy asserting of JSON content and so on...
There could be a lot written about how to use any particular slice but hopefully these simple tips will help you to use them better.