Getting Started with Component Testing with WireMock
What is component testing?
The component test is a stage of the Test Pyramid which focuses on testing individual software components or modules in isolation from the rest of the system. It is a type of testing that focuses on verifying the functionality, performance, and reliability of each component separately to ensure that it meets its specified requirements.
Annotations
@SpringBootTest(classes = TestServiceApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(locations = {"classpath:application-test.yml", "classpath:bootstrap-test.yml"})
@Tag("integration")
@ActiveProfiles("test")
@WireMockTest
- SpringBootTest: It is used to launch the entire Spring Boot application context and test the application as a whole, including all the components and dependencies.
- TestPropertySource: It is used to specify the properties for a test class or method. It is used to override the default properties of the application or to provide additional properties for testing purposes.
- Tag (Optional): This is a optional property which can be used to separate running test in component test and JUnit test stages.
- ActiveProfiles: It is used to specify the active profiles for a test class or method. It is used to activate specific profiles for testing purposes so that we can modify the test configuration for different scenarios.
- WireMockTest: It is used to mock the HTTP responses from external services or APIs.
Steps for creating the Test Module
- Create the MyComponentTest.java file with the annotations as given below.
@SpringBootTest(classes = TestServiceApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(locations = {"classpath:application-test.yml", "classpath:bootstrap-test.yml"})
@Tag("integration")
@ActiveProfiles("test")
@WireMockTest
public class MyComponentTest {
}
2. Define a variable for WebClient for making call to your Application.
private WebClient webClient;
3. Define a mock Server using WireMock.
private WireMockServer testMockServer;
3. Initialize webClient and testMockServer and configure them in @BeforeEach.
@BeforeEach
public void setup() {
testMockServer = new WireMockServer(options().port(8444));
testMockServer.start();
webClient = WebClient.builder()
.baseUrl("http://localhost:" + port)
.defaultHeader(HttpHeaders.AUTHORIZATION, "Authorization Token")
.build();
}
4. Define a teardown function to cleanup the server configuration.
@AfterEach
public void teardown() {
testMockServer.stop();
}
5. Write a test to check the end to end flow.
@Test
@DisplayName("Test through Rest API Call")
public void test_forCreateApprovalGroupRest() {
testMockServer.stubFor(post(urlEqualTo("/v1/getVal"))
.willReturn(aResponse()
.withStatus(200)
.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.withBody("{\"message\":\"Hello, world!\"}")));
TestRequestPayload testRequest =
new TestRequestPayload(id, val);
Response res = webClient
.post()
.uri("/v1/test")
.body(Mono.just(testRequest), TestRequestPayload.class).retrieve().bodyToMono(
Response.class).block();
Assertions.assertNotNull(res);
}
Explanation:
A. For mocking the testMockServer,
- post(): Specify the method for the request
- urlEqualTo(): Give the endpoint of communication with the external server
- willReturn(): Specify the response
- aResponse(): It is a static method in the WireMock library that is used to create a mock HTTP response for testing purposes
- withStatus(): Define the statusCode for the response
- withHeader(): Add header for the response.
- withBody(): Body for the response
testMockServer.stubFor(post(urlEqualTo("/v1/getVal"))
.willReturn(aResponse()
.withStatus(200)
.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.withBody("{\"message\":\"Hello, world!\"}")));
B. Use the webClient to make a API call to the Application, where /v1/test is one of the endpoints in the Controller.
Response res = webClient
.post()
.uri("/v1/test")
.body(Mono.just(testRequest), TestRequestPayload.class).retrieve().bodyToMono(
Response.class).block();
How to run the Component test
mvn clean test -Dgroups=integration -s settings.xml