【问题标题】:Instantiate different cache manager in each Test Class在每个测试类中实例化不同的缓存管理器
【发布时间】:2015-04-28 00:22:21
【问题描述】:

在我的 Spring-Boot Web 应用程序项目中,我使用 Spring Cache 来实现缓存。可以通过application.yml 中定义的配置键启用/禁用缓存。我已经有现有的测试用例,在这些测试用例中假设没有缓存。因此,默认情况下,我的 integration-test 配置文件缓存被禁用,我初始化 NoOpCacheManager 并且我的所有测试都正常工作。

@Profile(value = { "default", "production", "integration-test" })
@Configuration
@EnableCaching(mode = AdviceMode.ASPECTJ)
public class CacheBeanConfig extends CachingConfigurerSupport {

    @Autowired
    private CacheConfig cacheConfig;

    @Bean
    @Override
    public CacheManager cacheManager() {
        if (cacheConfig.isEnabled()) {
            System.out.println("****************Couchbase CacheBeanTestsConfig cache init.**********************");
            Map<String, DeclaraCouchbaseTemplate> cacheCouchTemplateMap = Maps.newHashMap();
            Map<String, Integer> cacheTtlMap = Maps.newHashMap();

            for (CacheConfig.CacheConfigParam cacheParam : cacheConfig.getCaches()) {
                try {
                    cacheCouchTemplateMap.put(cacheParam.getName(),
                        couchbaseManager.getCouchbaseTemplate(cacheParam.getName()));
                    cacheTtlMap.put(cacheParam.getName(), cacheParam.getTtl());
                } catch (IOException | URISyntaxException e) {
                    throw new FaultException("Unable to get couchbase template.");
                }
            }

            return new CouchbaseCacheManager(cacheCouchTemplateMap, cacheTtlMap, metricRegistry);
        } else {
            System.out.println("****************NoOp CacheBeanTestsConfig cache init.**********************");
            NoOpCacheManager noopCacheManager = new NoOpCacheManager();
            return noopCacheManager;
        }
    }

}

我还想编写测试来验证缓存功能。我创建了一个CachedControllerTest 类,其中编写了所有缓存特定的测试。

问题是当我运行时

mvn test -Dtest=CachedControllersTest -Dspring.profiles.active=integration-test

CachedControllerTest 类中的所有测试都失败了,因为缓存管理器是用NoOpCacheManager 初始化的,即使我在 bean 函数中启用了缓存。

我尝试为 CachedControllerTest 创建单独的配置文件,但它仍然失败,因为一旦 cacheManager bean 被初始化,它就不会被重置。

mvn test -Dtest=CachedControllersTest -Dspring.profiles.active=integration-test,integration-cache-test

这是我的 CachedControllerTest 类

@ActiveProfiles("integration-cache-test")
@DirtiesContext
public class CachedControllersTest extends AbstractRestControllerTest {

    @Configuration
    @EnableCaching(mode = AdviceMode.ASPECTJ)
    @Profile("integration-cache-test")
    public static class CachedControllerTestsBeanConfig {

        @Autowired
        private CouchbaseManager couchbaseManager;

        @Autowired
        private CacheConfig cacheConfig;

        @Autowired
        private MetricRegistry metricRegistry;

        @Autowired
        GlobalApplicationConfig globalAppConfig;

        @Bean
        public CacheManager cacheManager() {
            System.out.println("**************** CachedControllerTestsBeanConfig EnabledCaching**********************");
            cacheConfig.setEnabled(true);
            if (cacheConfig.isEnabled()) {
                System.out.println("****************Couchbase CachedControllerTestsBeanConfig cache init.**********************");
                Map<String, DeclaraCouchbaseTemplate> cacheCouchTemplateMap = Maps.newHashMap();
                Map<String, Integer> cacheTtlMap = Maps.newHashMap();

                for (CacheConfig.CacheConfigParam cacheParam : cacheConfig.getCaches()) {
                    try {
                        cacheCouchTemplateMap.put(cacheParam.getName(),
                            couchbaseManager.getCouchbaseTemplate(cacheParam.getName()));
                        cacheTtlMap.put(cacheParam.getName(), cacheParam.getTtl());
                    } catch (IOException | URISyntaxException e) {
                        throw new FaultException("Unable to get couchbase template.");
                    }
                }

                return new CouchbaseCacheManager(cacheCouchTemplateMap, cacheTtlMap, metricRegistry);
            } else {
                System.out.println("****************NoOp CachedControllerTestsBeanConfig cache init.**********************");
                NoOpCacheManager noopCacheManager = new NoOpCacheManager();
                return noopCacheManager;
            }
        }

        @Bean(name = "mtlKeyGenerator")
        public KeyGenerator keyGenerator() {
            System.out.println("****************CachedControllerTestsBeanConfig mtlKeyGenerator.**********************");
            return new MultiTenantKeyGenerator(globalAppConfig.getTenantId());
        }

        @Bean(name = CacheManagementConfigUtils.CACHE_ASPECT_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public AnnotationGroupCacheAspect cacheAspect() {
            AnnotationGroupCacheAspect cacheAspect = AnnotationGroupCacheAspect.aspectOf();
            CacheManager cacheManager = (CacheManager) StaticContextHolder.getApplicationContext().getBean("cacheManager");
            cacheAspect.setCacheManager(cacheManager);

            KeyGenerator keyGenerator = (KeyGenerator) StaticContextHolder.getApplicationContext().getBean("mtlKeyGenerator");
            cacheAspect.setKeyGenerator(keyGenerator);
            return cacheAspect;
        }
    }

    @Component
    public static class StaticContextHolder implements ApplicationContextAware {

        private static ApplicationContext appContext;

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            appContext = applicationContext;
        }

        public static ApplicationContext getApplicationContext() {
            return appContext;
        }
    }
}

应用程序.yml

spring:
    profiles: integration-test

cache:
    enabled: false
---
spring:
    profiles: integration-cache-test

cache:
    enabled: false 

我的要求是为每个测试类重新初始化 cacheManage,而 CacheConfig 是我要在运行时修改的 bean,以便可以初始化适当的 CacheManager

如果我单独运行 CachedControllerTest 类测试,它们都会通过,因为在此之前没有其他测试类运行会将 cacheManager 初始化为 NoOpCacheManager。

在此先感谢您提供任何帮助/建议来解决这种情况。

编辑 1

根据 Sam 的建议,添加了 @ActiveProfiles

编辑 2

AbstractRestControllerTest 类定义

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class AbstractRestControllerTest {
}

【问题讨论】:

  • 仅供参考:AFTER_CLASS 是默认的ClassMode。因此,没有理由用默认值覆盖默认值。换句话说,类级别的空 @DirtiesContext 声明就足够了。
  • 感谢@SamBrannen 的提示。
  • 您使用的是StaticContextHolder吗?如果是这样,它是如何作为 Spring bean 被拾取的——通过组件扫描?

标签: spring-boot spring-test spring-cache


【解决方案1】:

@Profile 对测试类的影响

要为集成测试设置活动 bean 定义配置文件,您需要使用来自spring-testmodule 的@ActiveProfiles

有关详细信息,请参阅 Spring 参考手册的 Context configuration with environment profiles 部分。

另外,CachedControllerTestsBeanConfig 必须用 @Configuration 注释 @Component

问候,

Sam(Spring TestContext 框架的作者

【讨论】:

  • 在 CachedControllerTest 类上添加了@ActiveProfiles("integration-cache-test")。但是后续的测试类使用CachedControllersTest类初始化的缓存管理器。 DirtiesContext 仅添加到 @CachedControllersTest。我在想在CachedControllersTest 之后执行测试的其他测试类将使用NoOpCacheManager。但是它们失败了,因为数据是从缓存中提供的,并且所有的断言都失败了。
  • AbstractRestControllerTest(及其任何超类)是如何配置的?它使用@ContextConfiguration吗?它是否使用 Spring Boot 的@SpringApplicationConfiguration?等
  • 如何在测试中将CacheBeanTestsConfig 拾取(即声明)为配置类?
  • CachedControllerTestsBeanConfig 是如何被选为配置类的?
  • 如果你错过了我的更新:CachedControllerTestsBeanConfig 必须用@Configuration 注释,而不是@Component
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
相关资源
最近更新 更多