使用MockK模拟Spring Repository时出现Object无法转Task类转换异常
问题原因
- 核心原因是MockK的
relaxed = true规则对有返回值的泛型方法处理存在默认限制:CrudRepository.save()方法的返回值是泛型类型<S extends T> S,你的TaskRepository对应的返回类型是Task,但relaxed mock默认会为未打桩的非void方法返回基础的Any类型对象,Kotlin运行时会尝试将这个Any对象强转为Task,直接触发类型转换异常。 - 而
delete()方法是无返回值的(void)方法,不存在返回值类型转换的问题,因此可以正常执行。
解决方案
你只需要为TaskRepository的save方法手动打桩,指定符合类型要求的返回值即可,修改后的测试代码如下:
//TaskServiceTest.kt internal class TaskServiceTest { private val taskRepository: TaskRepository = mockk(relaxed = true) private val taskService = TaskService(mockk(relaxed = true), taskRepository) @Test fun `should remove subtask of parent task`() { val subTask: Task = mockk() val parentTask: Task = mockk() // 给save方法打桩,返回传入的Task对象即可解决类型转换问题 every { taskRepository.save(any<Task>()) } answers { firstArg() } // 给parentTask的subTasks打桩,否则remove调用不会执行,验证会失败 every { parentTask.subTasks } returns mutableListOf(subTask) every { parentTask.subTasks?.remove(subTask) } returns true taskService.deleteSubTask(parentTask, subTask) verify { parentTask.subTasks?.remove(subTask) } verify { taskRepository.delete(subTask) } verify { taskRepository.save(parentTask) } } }
如果不想给每个Repository的save方法单独打桩,也可以在创建mock时使用更宽松的返回值策略,指定泛型返回值的默认生成规则。
额外提示:你当前的业务代码逻辑顺序有问题,先执行
save(parentTask)再移除子任务,会导致子任务移除的变更不会被持久化到数据库,建议调整顺序为先修改父任务的子任务列表,再执行save操作。
内容的提问来源于stack exchange,提问作者xetra11
相关产品推荐
相关产品推荐

