Skip to content
Advertisement

Is it possible to retrieve value from application.properties without autowiring the class under test?

I have a test class that is annotated with @Spy and @InjectMocks and tested using Mockito. The class under test has a value (url) that is retrieved from the application.properties file. I’d like to test whether this url is being set correctly within the method that uses it. I can do this if I remove the @Spy and @InjectMocks annotations and use @Autowire and @SpringBootTest. However, that breaks other tests that use the spy functionality, so I’m just wondering if there’s any way we can keep the spy working and test all our methods inside the same file, maybe without the need to bring in the @SpringBootTest annotation and the autowiring? The workaround we’re using for now is to have two files, one that uses the spy and the other that tests the specific method to do with the properties file and that requires the full context to load, but not sure that’s the best solution here?

Here is the test with the spy:

@ExtendWith(MockitoExtension.class)
class ProviderHelperServiceTest {

    @Spy
    @InjectMocks
    ProviderHelperService providerHelperService;
    
    @Value("${viaduct-url}")
    String viaductUrl;
    
    @Test
    void testGetRequestBodyUriSpec() {
        WebClient.RequestBodyUriSpec requestBodyUriSpec = providerHelperService.getRequestBodyUriSpec("sifToken");
        
        final String[] url = new String[1];
        requestBodyUriSpec.attributes(httpHeaders -> {
            url[0] = (String) httpHeaders.get("org.springframework.web.reactive.function.client.WebClient.uriTemplate");
        });

        // Fails as url[0] comes back as null. Disabled and moved to another file.
        assertEquals(viaductUrl, url[0]);
    }
@SpringBootTest
class ProviderHelperService2Test {

    @Autowired
    ProviderHelperService providerHelperService;

    @Value("${viaduct-url}")
    String viaductUrl;

    @Test
    void testGetRequestBodyUriSpec() {

        WebClient.RequestBodyUriSpec requestBodyUriSpec = providerHelperService.getRequestBodyUriSpec("sifToken");
        
        final String[] url = new String[1];
        requestBodyUriSpec.attributes(httpHeaders -> {
            url[0] = (String) httpHeaders.get("org.springframework.web.reactive.function.client.WebClient.uriTemplate");
        });

       assertEquals(viaductUrl, url[0]);
    }
}

And here is the method under test:

public class ProviderHelperService {

    @Value("${viaduct-url}")
    String viaductUrl;
    
    
    public WebClient.RequestBodyUriSpec getRequestBodyUriSpec(String sifToken) {
        WebClient.RequestBodyUriSpec requestBodyUriSpec = WebClient.create().post();
        requestBodyUriSpec.header("Authorization", sifToken);
        requestBodyUriSpec.uri(viaductUrl);
        return requestBodyUriSpec;
    }

}

Advertisement

Answer

The cleanest way to perform such tests is to replace field injection with constructor injection, and then you can quite easily confirm that the value that’s passed into the class comes back out the service call.

If you’re using Boot, it’s usually best to replace use of @Value with @ConfigurationProperties. Depending on the specifics, you can either pass the whole properties object to the service’s constructor or write an @Bean configuration method that unpacks the relevant properties and passes them as plain constructor parameters with new.

Advertisement