Spring Boot testing - Focus on your changes

Jan 31, 2022

Testing in Spring Boot

Time and time again we find ourselves in the situation of writing a new micro-service in SpringBoot. Part of the TDD process is to start writing tests first. As not all the times is possible to write the tests first, we will go back and add the tests after we wrote the code. As there are many reasons to not do that, I will not enumerate them here. Let’s focus on how to test what matters, versus testing what was already tested.

Imports omitted for code brevity.

Initial Java code

package com.georgeracu.blog.springboot.application.config;

public class CustomWebMvcConfigurer implements WebMvcConfigurer {
    
    @Value("${config.origins.allowed}")
    private String allowedOrigins;

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        if(StringUtils.isNotEmpty(allowedOrigins)) {
            registry
                .addMapping("/**")
                .allowedOrigins(allowedOrigins.split(","));

        }
    }
}

Once our production code has been written, let’s see how a test could look like.

package com.georgeracu.blog.springboot.application.config;

class CustomWebMvcConfigurerTest {
    private CustomWebMvcConfigurer configurer;
    private TestCorsRegistry registry;

    @BeforeEach
    void setup() {
        configurer = new CustomWebMvcConfigurer();
        registry = new TestCorsRegistry();
    }

    @ParameterizedTest
    @MethodSource("argsForCorsProvider")
    void shouldAddCorsMappingsWhenEnabled(String allowedOrigins, int expectedSize) {
        // arrange
        ReflectionTestUtils.setField(configurer, "allowedOrigins", allowedOrigins);

        // act
        configurer.addCorsMappings(registry);

        // assert
        assertEquals(1, registry.getCorsConfigurations().size());
    }

    private static Stream<Arguments> argsForCorsProvider() {
        return Stream.of(Arguments.of("http://example.com", 1));
    }

    class TestCorsRegistry extends CorsRegistry {
        public Map<String, CorsConfiguration> getCorsConfiguration() {
            return super.getCorsConfiguration();
        }
    }
}

So far, we wrote a test that is testing that our CORS origins are added to the list of allowed origins. All nice and simple, but a few observations:

  • The test is testing that the CorsRegistry adds a mapping to the list of the allowed origins. This feels that it was tested already by the creators of the framework;
  • We are not focusing that we actually tested our custom code: adding several values to the list of the allowed origins;
  • The class TestCorsRegistry is not needed when there are powerful mocking frameworks that allow us to mock that object and assert that custom behavior has happened on the mock itself;
  • Field injection is in our way of actually writing simpler unit tests;

Lets’s see how this code would look like with a bit of refactoring.

package com.georgeracu.blog.springboot.application.config;

@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
    
    private String allowedOrigins;

    public CustomWebMvcConfigurer(@Value("${config.origins.allowed}") String allowedOrigins) {
        this.allowedOrigins = allowedOrigins;
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        if(StringUtils.isNotEmpty(allowedOrigins)) {
            registry
                .addMapping("/**")
                .allowedOrigins(allowedOrigins.split(","));

        }
    }
}
package com.georgeracu.blog.springboot.application.config;

class CustomWebMvcConfigurerTest {
    private CustomWebMvcConfigurer configurer;
    private CorsRegistry registry;
    private CorsRegistration corsRegistration;

    @BeforeEach
    void setup() {
        registry = Mockito.mock(CorsRegistry.class);
        corsRegistration = Mockito.mock(CorsRegistration.class);
    }

    @ParameterizedTest
    @MethodSource("argsForCorsProvider")
    void shouldAddCorsMappingsWhenEnabled(String allowedOrigins) {
        // arrange
        when(registry.addMapping("/**")).thenReturn(corsRegistration);
        configurer = new CustomWebMvcConfigurer(allowedOrigins);

        // act
        configurer.addCorsMappings(registry);

        // assert
        verify(registry).addMapping("/**");
        verify(corsRegistration).allowedOrigins(allowedOrigins);
    }

    private static Stream<Arguments> argsForCorsProvider() {
        return Stream.of(Arguments.of("http://example.com"));
    }
}

Tags: programmingspring bootjavatesting

Archives

  1. February 2024
  2. Maximizing Software Development Productivity: The Power of Flow and Minimizing Interruptions
  3. December 2023
  4. Clean Code in Java: Writing Code that Speaks
  5. Clean Code in Java: A concise guide
  6. Understanding Value Objects in Java: A Brief Guide
  7. August 2023
  8. Consuming RabbitMQ Messages with Clojure: A Step-by-Step Tutorial with Tests
  9. January 2023
  10. Running a Spring Boot service with kubernetes
  11. December 2022
  12. Hosting a PWA with Jekyll and Github pages
  13. November 2022
  14. Global Day of Code Retreat
  15. Facilitating a mini Code Retreat
  16. October 2022
  17. The Curse of Optional
  18. September 2022
  19. Testing Spring Boot Microservices - Presentation
  20. March 2022
  21. TDD Workshop
  22. February 2022
  23. Value Objects in Java
  24. Efficient Java
  25. January 2022
  26. Spring Boot testing - Focus on your changes
  27. Product users - Personas
  28. December 2021
  29. Write code fit for testing
  30. November 2020
  31. Running a Spring Boot app with kubernetes
  32. September 2019
  33. Setup GPG on Mac and sign git repositories
  34. July 2019
  35. Running a Clojure Pedestal application on Raspberry Pi model B revision 2
  36. Clojure from zero to hero (part 3) - First endpoint
  37. Clojure from zero to hero (part 2) - A bit of syntax
  38. June 2019
  39. Clojure from zero to hero (1) - explaining project.clj
  40. Clojure from zero to hero (0) - creating a Pedestal app
  41. November 2017
  42. Introduction to Docker
  43. April 2015
  44. Git micro commits
  45. July 2014
  46. Google Glass Development - setup tools, environment and turn on debugging on Glass
  47. June 2013
  48. How To: Get the rendered HTML of a webpage with Python
  49. Set union of two lists in Python