Spring Testing Quick Reference: Essential Tips for Seamless Unit and Integration Testing

2024-07-03

In this blog post, we'll explore how to effectively write integration tests for a Spring Boot controller using the TestRestTemplate. This approach allows developers to test the full stack of a web application, ensuring that the endpoints behave as expected.

Key Components

Setup of the Integration Test

In our example, we are testing the AdapterPaymentPluginController. The class is annotated with @SpringBootTest, which allows Spring to load the full application context for testing. We're using a random port to avoid conflicts with other applications.

Code Breakdown

@SpringBootTest(classes = App.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class AdapterPaymentPluginControllerITest {
    
    @LocalServerPort
    int port;

    final String path = "/adapter-payments-plugins/";

    @Autowired
    TestRestTemplate restTemplate;

    String accessToken;

    @BeforeEach
    void setUp() throws JsonProcessingException {
        var u = "https://example.com/v1/token";
        var clientId = ""; // specify client id
        var secret = ""; // specify secret key
        var channel = ""; // specify channel
        var scope = "read";
        
        var h = new HttpHeaders();
        h.setAll(Map.of("client_id", clientId, "client_secret", secret, "channel", channel, "scope", scope));
        h.setContentType(MediaType.APPLICATION_JSON);
        
        var b = "{\"name\": \"tiago\", \"login\": \"username\", \"system\": \"\", \"scope\": \"\"}";
        var e = new HttpEntity<>(b, h);
        
        var r = restTemplate.exchange(u, HttpMethod.POST, e, String.class);
        accessToken = (String) new ObjectMapper().readValue(r.getBody(), Map.class).get("access_token");
    }

Explanation:

Testing Scenarios

1. Testing Forbidden Access

@Test
void testEndpointForbidden() {
    String url = "http://localhost:" + port + path + "/1";
    
    var res = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, null), String.class);

    assertThat(res).isNotNull();
    assertSame(HttpStatus.FORBIDDEN, res.getStatusCode());
}

2. Testing Not Found Scenario

@Test
void testEndpointNotFound() {
    String url = "http://localhost:" + port + path + "/1";
    var headers = new HttpHeaders();
    headers.setAll(Map.of("Authorization", accessToken));
    headers.setContentType(MediaType.APPLICATION_JSON);

    var res = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), String.class);

    assertThat(res).isNotNull();
    assertSame(HttpStatus.NOT_FOUND, res.getStatusCode());
}

Conclusion

Writing integration tests for Spring Boot controllers helps ensure that your application behaves correctly under various conditions. By leveraging TestRestTemplate, we can simulate HTTP requests and verify responses effectively. The structure shown demonstrates how to set up tests for both forbidden access and handling non-existent resources.

This testing methodology is essential for maintaining the integrity of your application as it evolves.