An integration test, @SpringBootTest, load the whole of Spring application context. According to observations from the output. It initiates a database connection and a real web server listening on the ports (I see a Tomcat server starts on the port 8080). However, via @SpringBootTest attributes, the web environment can be re-configured. By default, the web environment should be mock. On such a setup, a mocked servlet container is initiated, rather than a real application server.
Two major annotations construct a typical Spring Boot (I am using 1.5 release right now) integration test. It looks like this:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyTest {
// ...
}
@RunWith(SpringRunner.class)tells JUnit to run using Spring’s testing support.SpringRunneris the new name for,SpringJUnit4ClassRunnerit’s just a bit easier on the eye.@SpringBootTestis saying “bootstrap with Spring Boot’s support” (e.g. loadapplication.propertiesand give me all the Spring Boot goodness)- The attribute
webEnvironmentallows specific “web environments” to be configured for the test. You can start tests with aMOCKservlet environment or with a real HTTP server running on either aRANDOM_PORTor a.DEFINED_PORT - If we want to load a specific configuration, we can use the attribute
classesof@SpringBootTest. In this example, we’ve omitted meansclassesthat the test will first attempt to load@Configurationfrom any inner-classes, and if that fails, it will search for your primary@SpringBootApplicationclass.
There is another way to test without a server on but having the whole of Spring context(I can see all controller and its method having been mapped.), i.e. using @AutoConfigureMockMvc together with @SpringBootTest to inject a MockMvc instance. Spring uses this MockMVC to send HTTP requests into the DispatcherServlet, instead of a Test Rest Template), and then hand it off to controllers. It explains there is no need to have a real server on.
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ApplicationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello World")));
}
}
We may also test without turning sever on, and load partially Spring context(for a single controller). By this way, we may narrow down the test to a web layer alone, by using @WebMvcTest.
@RunWith(SpringRunner.class)
@WebMvcTest
public class WebLayerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello World")));
}
}
- When you start testing real systems, you often find it’s helpful to mock out specific beans. Common scenarios for mocking include simulating services that you can’t use when running tests, or testing failure scenarios that are difficult to trigger in a live system.
With Spring Boot 1.4 you can easily create a Mockito mocks that can replace an existing bean, or create a new one:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleTestApplicationWebIntegrationTests {
@Autowired
private TestRestTemplate restTemplate;
@MockBean
private VehicleDetailsService vehicleDetailsService;
@Before
public void setup() {
given(this.vehicleDetailsService.
getVehicleDetails("123")
).willReturn(
new VehicleDetails("Honda", "Civic"));
}
@Test
public void test() {
this.restTemplate.getForEntity("/{username}/vehicle",
String.class, "sframework");
}
}
In this example we’re:
- Creating a Mockito mock for
VehicleDetailsService. - Injecting it into the
ApplicationContextas a bean using @MockBean - Injecting it into the field in the test.
- Stubbing behavior in the
setupmethod. - Trigger something that will ultimately call the mock.
Mocks will be automatically reset across tests. They also form part of the cache key used by Spring Test (so there’s no need to add
@DirtiesContext)
Spies work in a similar way. Simply annotate a test field with
@SpyBean to have a spy wrap any existing bean in the ApplicationContext.What is Spring Application Context?
The
ApplicationContext provides:- Bean factory methods for accessing application components.
- The ability to load file resources in a generic fashion.
- The ability to publish events to registered listeners.
- The ability to resolve messages to support internationalization.
- Inheritance from a parent context.
References:
Spring Test Document
Building REST services with Spring
For understanding test in Spring boot, the following link is a good one.
Testing improvements in Spring Boot 1.4
Building REST services with Spring
For understanding test in Spring boot, the following link is a good one.
Testing improvements in Spring Boot 1.4