Grzegorz Poznachowski
Grzegorz Poznachowski

Reputation: 644

Override application properties in Spring Boot integration tests

I'm preparing a Spring Boot starter (used in tests) and I want to override a specific application property. This particular case regards enabling / disabling cache based on a property (production-code starter uses @ConditionalOnProperty). When using the test starter I want to have the caching disabled by default.

Is there a way to do that except using @TestPropertySource? Hence it is not a repeatable annotation, I don't want to use it. It's a recommended way for end-user to add properties required for the test case.

Edit: I'm providing more details on the specific use case

Production Starter auto-configuration:

@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(StarterCacheProperties.class)
@EnableCaching
public class StarterCacheAutoConfiguration {

..(omitted for clarity)..

@Configuration
@ConditionalOnProperty(prefix = "neostarter.saasmgr.cache", name = "enabled", havingValue = "false")
public static class SaasMgrNoCacheConfig extends CachingConfigurerSupport {

    @Bean(name = SAAS_MGR_CACHE_MANAGER)
    @Override
    public CacheManager cacheManager() {
        return new NoOpCacheManager();
    }
}

@Configuration
@ConditionalOnProperty(prefix = "neostarter.saasmgr.cache", name = "enabled", matchIfMissing = true)
public static class SaasMgrCachingConfig extends CachingConfigurerSupport {

    @Autowired
    SaasMgrCacheProperties saasMgrCacheProperties;

    @Bean(destroyMethod = "shutdown")
    public net.sf.ehcache.CacheManager ehCacheManager() {
        CacheConfiguration cacheConfiguration = new CacheConfiguration(SAAS_MGR_AUTH_CACHE, 1000)
                .timeToLiveSeconds(saasMgrCacheProperties.getTimeToLiveSeconds());

        net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
        config.addCache(cacheConfiguration);

        return net.sf.ehcache.CacheManager.newInstance(config);
    }

    @Bean(name = SAAS_MGR_CACHE_MANAGER)
    @Override
    public CacheManager cacheManager() {
        return new EhCacheCacheManager(ehCacheManager());
    }
}

This gives user a choice of caching particular calls in production (or not). However, I find it reasonable to disable caching in tests by default. I am fully aware that this can still be overridden by end-user. In a test starter (different dependency) I tried the following:

@Configuration
@AutoConfigureBefore({CacheAutoConfiguration.class, SaasMgrSecurityAutoConfiguration.class})
public class DisableCacheAutoConfiguration {

    @Autowired
    Environment environment;

    @PostConstruct
    public void disableCache() {
        EnvironmentTestUtils.addEnvironment((ConfigurableEnvironment)environment, "neostarter.saasmgr.cache.enabled=false");
    }
}

but no matter what StarterCacheAutoConfiguration with EhCacheCacheManager is always resolved before DisableCacheAutoConfiguration. In debug in AutoConfigurationSorter.java I see proper order of the configuration:

15 = "com.neoteric.starter.auth.saasmgr.test.DisableCacheAutoConfiguration"
16 = "com.neoteric.starter.auth.SaasMgrSecurityAutoConfiguration"
36 = "org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration"

Upvotes: 2

Views: 2683

Answers (1)

Stephane Nicoll
Stephane Nicoll

Reputation: 33091

You can't change user's configuration in a starter, that would be way too opaque and invasive. You have no guarantee about it anyway: anybody could set the property value at a higher level (e.g. system property) and override what you're trying to change.

If you want to disable caching, the most easiest way to do it is to do what spring.cache.type=none does, that is providing an implementation of CacheManager that does not do anything.

Try to declare a bean of type org.springframework.cache.support.NoOpCacheManager

Upvotes: 1

Related Questions