【发布时间】: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