【问题标题】:Testing cache in Spring Data Jpa在 Spring Data Jpa 中测试缓存
【发布时间】:2021-12-04 21:35:58
【问题描述】:

我有一段代码,我在其中应用缓存来获取对象。

服务:

@Service
class UserServiceImpl(
    private val userRepository: UserRepository
) : UserService {

    override fun create(userEntity: UserEntity): UserEntity = userRepository.save(userEntity)
        .also { log.info("saved user {}", it) }

    @Cacheable("users", key = "#id")
    override fun get(id: Long): UserEntity = userRepository.findById(id)
        .orElseThrow { EntityNotFoundException("User not found by id $id") }
        .also { log.info("from db: received user {}", it) }

    companion object {
        private val log = KotlinLogging.logger { }
    }
}

存储库:

@Repository
interface UserRepository : JpaRepository<UserEntity, Long> {
}

我已经用一个简单的控制器验证了缓存运行良好,但我无法通过测试来验证这一点。测试失败并出现错误:Verification failed: call 1 of 1: UserRepository(#1).findById(eq(1))). 3 matching calls found, but needs at least 1 and at most 1 calls

class UserServiceImplTest {
    private val userRepository = mockkClass(UserRepository::class)
    private val userService: UserService = UserServiceImpl(userRepository)

    @Test
    fun `get should use caching`() {
        // given
        val user = UserEntity(1, "Anna", "anna@gmail.com")

        every { userRepository.save(user)} returns user
        every { userRepository.findById(user.id!!) } returns Optional.of(user)

        // when
        userService.get(user.id!!)
        userService.get(user.id!!)
        userService.get(user.id!!)

        // then
        verify(exactly = 1) { userRepository.findById(user.id!!) }
    }
}

也许我也需要为测试启用缓存。或者我的测试写错了(这很可能)。如何编写测试来检查缓存是否正常工作?

【问题讨论】:

    标签: unit-testing kotlin caching spring-data-jpa spring-test


    【解决方案1】:

    @Cacheable 将生成一个包装方法来进行缓存。这个包装器将存在于 Spring 生成的代理上,因此当您自己创建 UserServiceImpl 时它不会发挥作用。如果你想测试它,你需要让 Spring 上下文管理类,包括模拟。

    例如,

    @SpringBootTest
    class UserServiceImplTest {
        @MockBean
        lateinit var userRepository: UserRepository
    
        @Autowired
        lateinit var userService: UserService
    
        @Test
        fun `get should use caching`() {
            // given
            val user = UserEntity(1, "Anna", "anna@gmail.com")
    
            every { userRepository.save(user)} returns user
            every { userRepository.findById(user.id!!) } returns Optional.of(user)
    
            // when
            userService.get(user.id!!)
            userService.get(user.id!!)
            userService.get(user.id!!)
    
            // then
            verify(exactly = 1) { userRepository.findById(user.id!!) }
        }
    }
    

    【讨论】:

    • you need to let Spring context manage the classes, including the mock. - 我该怎么做?
    • 更新了答案以显示示例。不清楚您使用的是 MockK 还是 Mockito。对于 MockK,您需要改用 this dependency@MockkBean
    猜你喜欢
    • 2017-11-22
    • 2018-05-10
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    • 2013-11-14
    相关资源
    最近更新 更多