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.SpringRunner
is the new name for,SpringJUnit4ClassRunner
it’s just a bit easier on the eye.@SpringBootTest
is saying “bootstrap with Spring Boot’s support” (e.g. loadapplication.properties
and give me all the Spring Boot goodness)- The attribute
webEnvironment
allows specific “web environments” to be configured for the test. You can start tests with aMOCK
servlet environment or with a real HTTP server running on either aRANDOM_PORT
or a.DEFINED_PORT
- If we want to load a specific configuration, we can use the attribute
classes
of@SpringBootTest
. In this example, we’ve omitted meansclasses
that the test will first attempt to load@Configuration
from any inner-classes, and if that fails, it will search for your primary@SpringBootApplication
class.
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
ApplicationContext
as a bean using @MockBean - Injecting it into the field in the test.
- Stubbing behavior in the
setup
method. - 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
No comments:
Post a Comment