当前位置: 首页 > 知识库问答 >
问题:

在Kotlin和JUnit5中测试Spring Boot缓存

徐英锐
2023-03-14

我有一个简单的存储库,它的界面是用Kotlin写的,从数据库获得一个网站列表;并且我用Spring缓存缓存响应:

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)
}

现在我想测试缓存是否真的起作用。作为测试的基础,我使用了如何在Spring数据存储库上测试Spring的声明性缓存支持?但是直接实现会导致存储库是代理而不是存储库的错误。所以我现在的尝试是:

@ContextConfiguration
@ExtendWith(SpringExtension::class)
class RepositoryCacheTests {
  @MockBean
  private lateinit var repository: Repository

  @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(repository.sites()).thenReturn(listOf(site, anotherSite))

    repository.sites()

    // Assert
    assertThat(cache.getCache("sites")?.get("sites")).isNotNull
  }

但是缓存是空的,并且在第一次读取之后没有填充。我在设置中遗漏了什么?

更新:

使用George的建议,我更新了测试(和代码,以便更容易模仿)。我还必须在配置中为存储库添加@bean,因为不能自动执行。找不到“repository”类型的bean。没有它。

  @Cacheable(value = ["sites"], key = "'sites'")
  override fun sites(): List<String> = jdbcTemplate.query(sites) { rs, _ -> rs.getString("siteId") }
@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'

更新2:

正如George指出的,解决方案是(https://stackoverflow.com/a/44911329/492882和https://stackoverflow.com/a/44911329/492882)

  @Autowired
  private lateinit var repository: IRepository

共有1个答案

厍和颂
2023-03-14

您正在嘲笑您的测试主题存储库。这应该是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)
  }
 类似资料:
  • 基于此链接中的答案,创建了一个包含测试类的测试套件 返回错误 但是每个添加的测试类都有测试方法,并且单独运行

  • 我有一个工作环境,包括我不管理的bom和JUnit5测试,除非我从如果我从它们不会被maven surefire插件拾取。我阅读了许多部分,并在一个较小的项目中进行了测试,它的工作和拾取,我不知道该在这篇文章中包含什么,因此您有足够的信息来查看问题所在。此外,如果有人能解释我阅读的导入的幕后内容,JUnit 4和5都需要使用surefire即 与版本 我很感激。 注意到 < li >我的测试都在s

  • Web上使用Neo4j进行Spring集成测试的大多数示例仍然在JUnit4上,并且使用Neo4JRule。 我们如何为Neo4j+Spring+JUnit5创建一个设置?

  • 在Maven项目中,我有一些现有的测试依赖于JUnit4。由于多种原因,我无法在JUnit5中迁移这些测试。 本质上,一些测试依赖于使用JUnit4运行程序的库,代码迁移可能需要时间。 我同样希望用JUnit5创建新的测试类,它现在发布并提供了新的有趣的特性。 如何做到这一点?

  • 基本上,我只是想测试我的映射器,它应该是由MapStruct自动生成的。 我尝试了所有可能的注释,这个答案似乎是使用sprinboot和JUnit5的最佳解决方案,尽管它在我的eclipse中仍然不起作用,不知为什么它只是显示了一个如下所示的错误,即尽管它应该通过@mapper注释自动生成。例如,我也在使用Lombok注释和所有这些自动生成的方法,eclipse都能识别并工作得非常好。 那我做错了

  • 目前我的工作解决方案是: =3.0.0=5.2.0 然而,当我通过Maven运行测试时,JUnit5测试被忽略了。 编辑: 测试类为: