ClassCastException在使用Mockito模拟泛型类型时 [英] ClassCastException when mocking generic type using Mockito
问题描述
public abstract class AbstractCarTest< G> {
...
@Mock
保护G carMock;
...
}
我已经实现了一个具体的测试类它。
public class TruckTest extends AbstractCarTest< Truck> {
...
when(truckFactory.getTruck(anyString())。return(carMock);
...
}
方法签名看起来像这样
public Truck getTruck(String name);
运行 TruckTest
我得到一个 ClassCastException
说
java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer $ $$ ClassWithSuperclassToWorkAroundCglibBug $$ EnhancerByMockitoWithCGLIB ...不能转换到com.example.Truck
为什么会这样?我可以通过任何方式解决这个问题?
Mockito正在生成Mock是通过继承一个给定的类并覆盖它的所有方法而创建的(因此限制了不要模拟 final
类或方法)。在运行时,所有 AbstractCarTest 中,这是对象.htmlrel =nofollow>泛型类型被擦除
并被它们的上层类型边界替换。 ,因为你没有指定明确的上限。因此,Mockito将您的原始类视为:
public abstract class AbstractCarTest {
@Mock
保护对象carMock;
}
在运行时会创建一个模拟,扩展 Object
而不是您想要的卡车
类。 (你不能看到这个,因为cglib有一个bug,它不能直接扩展 Object
,相反,Mockito扩展了一个名为 ClassWithSuperclassToWorkAroundCglibBug
。)通常,编译器会在编译时发出类型错误,其中泛型类型仍然可用,但在运行时,您会遇到堆污染。
解决方法如下:
public abstract class AbstractCarTest< T> {
protected abstract T getCarMock();
//在这里定义一些使用泛型类型的基础测试用例。
}
public class TruckTest extends AbstractCarTest< Truck> {
@Mock
私人卡车carMock;
@Override
受保护的卡车getCarMock(){return carMock; }
...
when(truckFactory.getTruck(anyString())。return(getCarMock());
}
$ c $通过在不使用泛型的情况下定义你的模拟类型,你可以通过getter来从抽象基类访问模拟,其中模拟类型是正确的定义为卡车
。
I have a abstract test class with a generic parameter.
public abstract class AbstractCarTest<G> {
...
@Mock
protected G carMock;
...
}
I've implemented a concrete test class of it.
public class TruckTest extends AbstractCarTest<Truck> {
...
when(truckFactory.getTruck(anyString()).return(carMock);
...
}
The method signature looks like this
public Truck getTruck(String name);
When running TruckTest
I get a ClassCastException
saying
java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$... cannot be cast to com.example.Truck
Why is that? Any way I can work around that?
解决方案 Mockito is generating your mock class at runtime. Mocks are created by subclassing a given class and by overriding all of its methods. (Thus the limitation of not mocking final
classes or methods.) At runtime, all generic types are erased and replaced by their upper type bound, in your AbstractCarTest
this is Object
as you do not specify an explicit upper bound. Therefore, Mockito sees your raw class as:
public abstract class AbstractCarTest {
@Mock
protected Object carMock;
}
at runtime and will create a mock that extends Object
instead of your desired Truck
class. (You cannot see this because cglib has a bug where it cannot extend Object
directly. Instead, Mockito is extending an internal class called ClassWithSuperclassToWorkAroundCglibBug
.) Usually, the compiler would issue a type error at compile time where the generic type is still available but at runtime, you experience heap pollution instead.
A work around would be as follows:
public abstract class AbstractCarTest<T> {
protected abstract T getCarMock();
// define some base test cases here that use the generic type.
}
public class TruckTest extends AbstractCarTest<Truck> {
@Mock
private Truck carMock;
@Override
protected Truck getCarMock() { return carMock; }
// ...
when(truckFactory.getTruck(anyString()).return(getCarMock());
}
By defining your mocked type without using generics, you are able to access the mock from the abstract base class by a getter where the mocked type is correctly defined as Truck
.
这篇关于ClassCastException在使用Mockito模拟泛型类型时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!