在Kotlin和JUnit5中测试Spring引导缓存
我有一个简单的存储库,它的接口是用Kotlin编写的,用于从db获取站点列表;我使用Spring cache缓存响应:在Kotlin和JUnit5中测试Spring引导缓存,spring,spring-boot,kotlin,junit5,spring-cache,Spring,Spring Boot,Kotlin,Junit5,Spring Cache,我有一个简单的存储库,它的接口是用Kotlin编写的,用于从db获取站点列表;我使用Spring cache缓存响应: interface IRepository { fun sites(): List<String> } @Repository class Repository(private val jdbcTemplate: NamedParameterJdbcTemplate) : IRepository { private val sites = "SE
interface IRepository {
fun sites(): List<String>
}
@Repository
class Repository(private val jdbcTemplate: NamedParameterJdbcTemplate) : IRepository {
private val sites = "SELECT DISTINCT siteId FROM sites"
@Cacheable(value = ["sites"], key = "sites")
override fun sites(): List<String> = jdbcTemplate.jdbcTemplate.queryForList(sites, String::class.java)
}
但缓存是空的,并且在第一次读取后不会填充。我的设置中缺少什么
更新:
根据George的建议,我更新了测试(和代码,以便于模拟)。我还必须在配置中为存储库添加@Bean
,因为无法自动连线。找不到“Repository”类型的bean。
没有它
@Cacheable(value = ["sites"], key = "'sites'")
override fun sites(): List<String> = jdbcTemplate.query(sites) { rs, _ -> rs.getString("siteId") }
更新2:
正如乔治指出的,解决方案是(和)
您正在模拟您的测试主题
存储库
。这应该是Spring初始化的真实对象,因此它具有缓存。您需要模拟测试主体正在调用的JdbcTemplate
我真的不知道kotlin的语法,所以请耐心听我说。以下是您的测试应该是什么样子:
@ContextConfiguration
@ExtendWith(SpringExtension::class)
class RepositoryCacheTests {
@MockBean
private lateinit jdbcTemplate: NamedParameterJdbcTemplate
@Autowired
private lateinit var repository: IRepository
@Autowired
private lateinit var cache: CacheManager
@EnableCaching
@TestConfiguration
class CachingTestConfig {
@Bean
fun cacheManager(): CacheManager = ConcurrentMapCacheManager("sites")
}
@Test
fun `Sites is cached after first read`() {
// Arrange
whenever(jdbcTemplate.queryForList(any(), String::class.java)).thenReturn(listOf(site, anotherSite))
repository.sites()
// Assert
assertThat(cache.getCache("sites")?.get("sites")).isNotNull
//Execute again to test cache.
repository.sites()
//JdbcTemplate should have been called once.
verify(jdbcTemplate, times(1)).queryForList(any(), String::class.java)
}
1.什么是
repository.read(站点、区域设置)
?存储库
类中不存在此方法。2.当您试图从“模板”键检索时,repository.sites()
调用的结果存储在“site”键下的“site”缓存中。抱歉!我尽量简化这个问题的代码,并复制了错误的方法名。我更新了问题(仍然有效)你说的有道理!我试图听从你的建议,但失败了:(到底是什么失败了?我用你的建议和新的失败更新了问题(BeanNotOfRequiredTypeException for repository)根据这一点,您只需使用接口而不是类:repository:IRepository
是的,这就是答案。您希望我立即接受您的答案;还是希望更新它,使解决方案出现在答案中,而不出现在注释中?(使用repository:IRepository
@ContextConfiguration
@ExtendWith(SpringExtension::class)
class RepositoryCacheTests {
@MockBean
private lateinit var jdbcTemplate: NamedParameterJdbcTemplate
@Autowired
private lateinit var repository: Repository
@Autowired
private lateinit var cache: CacheManager
@EnableCaching
@TestConfiguration
class CachingTestConfig {
@Bean
fun testRepository(jdbcTemplate: NamedParameterJdbcTemplate): Repository = Repository(jdbcTemplate)
@Bean
fun cacheManager(): CacheManager = ConcurrentMapCacheManager("sites")
}
@Test
fun `Sites is cached after first read`() {
whenever(jdbcTemplate.query(any(), any<RowMapper<String>>())).thenReturn(listOf(site, anotherSite))
repository.sites()
assertThat(cache.getCache("sites")?.get("sites")).isNotNull
repository.sites()
verify(jdbcTemplate, times(1)).query(any(), any<RowMapper<String>>())
}
}
Error creating bean with name 'RepositoryCacheTests': Unsatisfied dependency expressed through field 'repository'; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'testRepository' is expected to be of type 'Repository' but was actually of type 'com.sun.proxy.$Proxy52'
@Autowired
private lateinit var repository: IRepository
@ContextConfiguration
@ExtendWith(SpringExtension::class)
class RepositoryCacheTests {
@MockBean
private lateinit jdbcTemplate: NamedParameterJdbcTemplate
@Autowired
private lateinit var repository: IRepository
@Autowired
private lateinit var cache: CacheManager
@EnableCaching
@TestConfiguration
class CachingTestConfig {
@Bean
fun cacheManager(): CacheManager = ConcurrentMapCacheManager("sites")
}
@Test
fun `Sites is cached after first read`() {
// Arrange
whenever(jdbcTemplate.queryForList(any(), String::class.java)).thenReturn(listOf(site, anotherSite))
repository.sites()
// Assert
assertThat(cache.getCache("sites")?.get("sites")).isNotNull
//Execute again to test cache.
repository.sites()
//JdbcTemplate should have been called once.
verify(jdbcTemplate, times(1)).queryForList(any(), String::class.java)
}