我开发了一个Spring数据存储库,MemberRepository
接口,扩展org.springframework.data.jpa.repository.JpaRepository
. MemberRepository
有一个方法:
@Cacheable(CacheConfiguration.DATABASE_CACHE_NAME)
Member findByEmail(String email);
结果由 Spring 缓存抽象缓存(由ConcurrentMapCache
).
我遇到的问题是我想编写一个集成测试(针对 hsqldb),断言结果是第一次从数据库检索 and 第二次从缓存中.
我最初想到嘲笑 jpa 基础设施(实体管理器等)并以某种方式断言实体管理器不会被第二次调用,但它似乎太难/麻烦了(请参阅https://stackoverflow.com/a/23442457/536299).
有人可以提供有关如何测试带有注释的 Spring Data Repository 方法的缓存行为的建议吗?@Cacheable
?
如果您想测试缓存等技术方面,则根本不要使用数据库。了解您想在这里测试什么非常重要。您希望确保避免使用相同参数的调用进行方法调用。面向数据库的存储库与本主题完全正交。
这是我的建议:
- 设置一个配置声明性缓存的集成测试(或从生产配置中导入必要的部分)。
- 配置存储库的模拟实例。
- 编写一个测试用例来设置模拟的预期行为,调用方法并相应地验证输出。
Sample
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class CachingIntegrationTest {
// Your repository interface
interface MyRepo extends Repository<Object, Long> {
@Cacheable("sample")
Object findByEmail(String email);
}
@Configuration
@EnableCaching
static class Config {
// Simulating your caching configuration
@Bean
CacheManager cacheManager() {
return new ConcurrentMapCacheManager("sample");
}
// A repository mock instead of the real proxy
@Bean
MyRepo myRepo() {
return Mockito.mock(MyRepo.class);
}
}
@Autowired CacheManager manager;
@Autowired MyRepo repo;
@Test
public void methodInvocationShouldBeCached() {
Object first = new Object();
Object second = new Object();
// Set up the mock to return *different* objects for the first and second call
Mockito.when(repo.findByEmail(Mockito.any(String.class))).thenReturn(first, second);
// First invocation returns object returned by the method
Object result = repo.findByEmail("foo");
assertThat(result, is(first));
// Second invocation should return cached value, *not* second (as set up above)
result = repo.findByEmail("foo");
assertThat(result, is(first));
// Verify repository method was invoked once
Mockito.verify(repo, Mockito.times(1)).findByEmail("foo");
assertThat(manager.getCache("sample").get("foo"), is(notNullValue()));
// Third invocation with different key is triggers the second invocation of the repo method
result = repo.findByEmail("bar");
assertThat(result, is(second));
}
}
正如您所看到的,我们在这里做了一些过度测试:
- 我认为最相关的检查是第二次调用返回第一个对象。这就是缓存的意义所在。使用相同键的前两次调用返回相同的对象,而使用不同键的第三次调用将导致存储库上的第二次实际调用。
- 我们通过检查缓存是否确实具有第一个键的值来加强测试用例。人们甚至可以扩展它来检查实际值。另一方面,我也认为避免这样做是可以的,因为您倾向于测试更多机制的内部而不是应用程序级别的行为。
要点
- 您不需要任何基础设施来测试容器行为。
- 设置测试用例既简单又直接。
- 精心设计的组件可让您编写简单的测试用例,并且需要较少的集成测试工作。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)