Generics Mockito:泛型父类上的ClassCastException
为了简化单元测试,我创建了以下父类:Generics Mockito:泛型父类上的ClassCastException,generics,kotlin,mockito,Generics,Kotlin,Mockito,为了简化单元测试,我创建了以下父类: internal abstract class TestUnitController<CONTROLLER: Any, SERVICE: Any> { @Mock protected lateinit var service: SERVICE @InjectMocks protected lateinit var controller: CONTROLLER protected abstract fu
internal abstract class TestUnitController<CONTROLLER: Any, SERVICE: Any> {
@Mock
protected lateinit var service: SERVICE
@InjectMocks
protected lateinit var controller: CONTROLLER
protected abstract fun controllerCall(): CONTROLLER.() -> Unit
protected abstract fun serviceCall(): SERVICE.() -> Any?
@Test
fun `when service returns error should throw ResponseStatusException`() {
testControllerServiceError(service, serviceCall()) { controllerCall() }
}
protected fun <U> testController(value: U, assertions: () -> Unit) {
testController(service, serviceCall(), value) { assertions() }
}
}
您遇到了Java的泛型类型擦除问题 当Mockito创建并注入mock时,
service
实际上看起来像一个简单的对象
或Any
:
protected lateinit var service: Any
因此,mock本身被创建为对象的mock
相反,我建议您在实际的测试类中包含与Mockito相关的所有内容
internal abstract class TestUnitController<CONTROLLER: Any, SERVICE: Any> {
protected abstract val service: SERVICE
protected abstract fun controllerCall(): CONTROLLER.() -> Unit
protected abstract fun serviceCall(): SERVICE.() -> Any?
@Test
fun `when service returns error should throw ResponseStatusException`() {
testControllerServiceError(service, serviceCall()) { controllerCall() }
}
protected fun <U> testController(value: U, assertions: () -> Unit) {
testController(service, serviceCall(), value) { assertions() }
}
}
内部抽象类TestUnitController{
受保护的抽象val服务:服务
受保护的抽象趣味控制器调用():控制器。(->单元
受保护的抽象趣味serviceCall():服务。(->有吗?
@试验
fun`when service returns error应该抛出ResponseStatusException`(){
testControllerServiceError(服务,serviceCall()){controllerCall()}
}
受保护的fun testController(值:U,断言:()->Unit){
testController(服务,serviceCall(),值){assertions()}
}
}
@RunWith(MockitoJUnitRunner::class)
内部类TestUnitCreateCompanyController:TestUnitController(){
@嘲弄
覆盖lateinit var服务:CompanyService
@注射模拟
私有lateinit var控制器:CreateCompanyController
私有val请求=公司创建请求(“LOL SARL”)
重写fun controllerCall():CreateCompanyController。(->Unit={createCompany(请求)}
重写fun serviceCall():CompanyService.(->Any?={createCompany(Any())}
@试验
fun`create company service成功时应返回created company`(){
val域=公司域(名称=请求.名称)
testController(域){
controller.createCompany(请求)。运行{
uuid.shouldEqual(domain.uuid.toString())
name.shouldEqual(域名)
}
}
}
}
完全正确!谢谢!只是一个小小的更正:TestUnitCreateCompanyController
的service
和controller
应该是特定类型,而不是泛型。
protected lateinit var service: Any
internal abstract class TestUnitController<CONTROLLER: Any, SERVICE: Any> {
protected abstract val service: SERVICE
protected abstract fun controllerCall(): CONTROLLER.() -> Unit
protected abstract fun serviceCall(): SERVICE.() -> Any?
@Test
fun `when service returns error should throw ResponseStatusException`() {
testControllerServiceError(service, serviceCall()) { controllerCall() }
}
protected fun <U> testController(value: U, assertions: () -> Unit) {
testController(service, serviceCall(), value) { assertions() }
}
}
@RunWith(MockitoJUnitRunner::class)
internal class TestUnitCreateCompanyController : TestUnitController<CreateCompanyController, CompanyService>() {
@Mock
override lateinit var service: CompanyService
@InjectMocks
private lateinit var controller: CreateCompanyController
private val request = CompanyCreateRequest("LOL SARL")
override fun controllerCall(): CreateCompanyController.() -> Unit = { createCompany(request) }
override fun serviceCall(): CompanyService.() -> Any? = { createCompany(any()) }
@Test
fun `when create company service successful should return created company`() {
val domain = CompanyDomain(name = request.name)
testController(domain) {
controller.createCompany(request).run {
uuid.shouldEqual(domain.uuid.toString())
name.shouldEqual(domain.name)
}
}
}
}