В моем проекте веб-приложения Spring-Boot я использую 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
, и он все еще терпит неудачу, потому что после инициализации bean-компонента cacheManager
он не сбрасывается.
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
По предложению Сэма добавлено @ActiveProfiles
.
Изменить 2
Определение класса AbstractRestControllerTest
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class AbstractRestControllerTest {
}
AFTER_CLASS
по умолчаниюClassMode
. Таким образом, нет причин переопределять значение по умолчанию значением по умолчанию. Другими словами, будет достаточно пустого объявления@DirtiesContext
на уровне класса. - person Sam Brannen   schedule 26.04.2015StaticContextHolder
? Если да, то как он определяется как Spring bean-компонент через сканирование компонентов? - person Sam Brannen   schedule 27.04.2015