我实际上正在尝试测试我的缓存机制。我正在使用咖啡因缓存。 测试:我两次调用缓存方法,并期望对多个方法调用具有相同的结果。即当我第二次使用相同签名对方法进行校准时,不应对应该从缓存中获取数据的方法进行校准。 问题:我的代码实际上两次调用了该方法。我在嘲笑我的仓库。如果有人解决了此类问题,请指导我。
我的仓库:
public class TemplateRepositoryOracle implements TemplateRepository
@Cacheable("Templates")
@Override
public Optional<NotificationTemplate> getNotificationTemplate(String eventTypeId, String destinationType, String destinationSubType) {}
测试:
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Ticker;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TemplateRepositoyOracleTest {
interface TemplateRepository {
@Cacheable("Templates")
Optional<Template> getNotificationTemplate(String eventTypeId, String destinationType, String destinationSubType);
}
@Configuration
@ConfigurationProperties(prefix = "caching")
@Data
@Slf4j
static class CacheConfiguration {
@Data
public static class CacheSpec {
private Integer expireAfterWrite;
}
private Map<String, CacheSpec> specs;
@Bean
public CacheManager cacheManager(Ticker ticker) {
SimpleCacheManager manager = new SimpleCacheManager();
if (specs != null) {
List<CaffeineCache> caches =
specs.entrySet().stream()
.map(entry -> buildCache(entry.getKey(),
entry.getValue(),
ticker))
.collect(Collectors.toList());
manager.setCaches(caches);
}
return manager;
}
private CaffeineCache buildCache(String name, CacheSpec cacheSpec, Ticker ticker) {
log.info("Cache {} specified timeout of {} min", name, cacheSpec.getExpireAfterWrite());
final Caffeine<Object, Object> caffeineBuilder
= Caffeine.newBuilder()
.expireAfterWrite(cacheSpec.getExpireAfterWrite(), TimeUnit.MINUTES)
.ticker(ticker);
return new CaffeineCache(name, caffeineBuilder.build());
}
@Bean
public Ticker ticker() {
return Ticker.systemTicker();
}
@Bean
TemplateRepository myRepo() {
return Mockito.mock(TemplateRepository.class);
}
}
@Autowired
CacheManager manager;
@Autowired
TemplateRepository repo;
@Test
public void methodInvocationShouldBeCached() {
Optional<Template> third = Optional.of(new NotificationTemplate(UUID.randomUUID(),"Test",DestinationType.SMS,"test","test",Optional.empty(),Optional.empty()));
Optional<Template> fourth = Optional.of(new NotificationTemplate(UUID.randomUUID(),"Test2",DestinationType.SMS,"test2","test2",Optional.empty(),Optional.empty()));
// the mock to return *different* objects for the first and second call
Mockito.when(repo.getNotificationTemplate(Mockito.any(String.class),Mockito.any(String.class),Mockito.any(String.class))).thenReturn(third);
// First invocation returns object returned by the method
Object result = repo.getNotificationTemplate("1","1","1");
assertThat(result, is(third));
// Second invocation should return cached value, *not* second (as set up above)
result = repo.getNotificationTemplate("1","1","1");
assertThat(result, is(third));
// Verify repository method was invoked once
Mockito.verify(repo, Mockito.times(1)).getNotificationTemplate("1","1","1");
assertThat(manager.getCache("notificationTemplates").get(""), is(notNullValue()));
// Third invocation with different key is triggers the second invocation of the repo method
result = repo.getNotificationTemplate("2","2","2");
assertThat(result, is(fourth));
}
}
属性文件:
缓存: 眼镜: 范本: expireAfterWrite:1440