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

使用Mockito模拟泛型类型时的ClassCastException

李华茂
2023-03-14

我有一个带有泛型参数的抽象测试类。

public abstract class AbstractCarTest<G> {
    ...
    @Mock
    protected 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$$... cannot be cast to com.example.Truck

为什么?我有什么办法可以解决这个问题吗?

共有3个答案

皇甫高阳
2023-03-14

只是想从@geoand的答案上改进一点。

public abstract class AbstractCarTest<G> {
    ...
    protected G carMock;
    ...

    @Before
    public void setUp() throws Exception {
        carMock= Mockito.mock(getClazz());
    }

    private Class<G> getClazz() {
        return (Class<G>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }
}


public class TruckTest extends AbstractCarTest<Truck> {
    ...
    when(truckFactory.getTruck(anyString()).return(carMock);
    ...
}

这最终消除了对抽象方法的需求。提供给 getActualTypeArguments() 的索引将取决于类型参数在声明中的显示位置。在大多数情况下,这将是0,但是如果你有这样的东西:

public abstract class AbstractCarTest<A, B, C, G>

如果您想使用< code>G的< code>Class,您需要提供< code>3的索引。

叶弘深
2023-03-14

Mockito似乎不会在不知道类是具体类型的情况下模拟类。

您可以通过执行以下操作来解决问题:

public abstract class AbstractCarTest<G> {
    ...
    protected G carMock;
    ...

    @Before
    public void setUp() throws Exception {
        carMock= Mockito.mock(getClazz());
    }

    protected abstract Class<G> getClazz();
}


public class TruckTest extends AbstractCarTest<Truck> {
    ...
    when(truckFactory.getTruck(anyString()).return(carMock);
    ...

    @Override
    protected Class<Truck> getClazz() {
        return Truck.class;
    }
}
阳狐若
2023-03-14

Mockito正在运行时生成您的模拟类。Mocks是通过对给定类进行子类化并覆盖其所有方法来创建的。(因此不嘲笑最终类或方法的限制。)在运行时,所有泛型类型都被擦除并替换为它们的上限类型,在您的AbstractCarTest中,这是Object,因为您没有指定显式上限。因此,Mockito将您的原始类视为:

public abstract class AbstractCarTest {

  @Mock
  protected Object carMock;
}

在运行时,并将创建一个扩展Object而不是您想要的Truck类的mock。(您看不到这一点,因为cglib有一个错误,它无法直接扩展Object。相反,Mockito正在扩展一个名为ClassSusSuperclass ToWorkAroundCglibBug的内部类。)通常,编译器会在编译时发出类型错误,其中泛型类型仍然可用,但在运行时,您会遇到堆污染。

解决方法如下:

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

通过在不使用泛型的情况下定义模拟类型,您可以通过getter从抽象基类访问模拟,其中模拟类型被正确定义为Truck

 类似资料:
  • 我正试图模拟一个泛型方法,但无论我做什么尝试,都会得到类转换异常。正在测试的类是 而测试类是 其他帮助器类和接口有: 此外,出现此错误的原因可能是:1。您使用final/private/equals()/hashCode()方法中的任一个作为存根。这些方法不能被截取/验证。不支持在非公共父类上声明的模拟方法。2.内部when()不是对mock而是对其他对象调用method。

  • 问题内容: 我正在使用Mockito 1.9.5。我有以下代码: 我收到一句编译错误: 但是,当我使用模拟方法时,不会出现错误。谁能告诉我怎么回事?使用该方法时为什么会出现错误?当第三方提供且无法修改时,还有其他方法可以解决此问题吗? 问题答案: 编辑 :从Mockito 1.10.x开始,嵌入在类中的泛型类型现在由Mockito用于深层存根。即。 Mockito尽最大努力获取编译器嵌入的类型信息

  • 我试图模拟Spring Rest的方法。 在同一个测试中,我有多个调用,它们的不同之处在于返回类型。 mock不考虑的泛型参数,最后定义的mock胜过前者。 有什么办法能让它起作用吗?

  • 我正在使用Mockito编写单元测试,但我在模仿注入的类时遇到了问题。问题是两个注入的类是相同的类型,仅通过它们的注释来区分。如果我试图简单地模拟,那么在我的测试中,该模拟不会被注入,并且该对象为。我如何模拟这些对象?

  • 我在我的一个实用程序类中有一个方法,它接受一个集合和一个类对象,并返回一个Iterable实例,该实例可以遍历作为指定类实例的集合的所有成员。其签名为: 这对于大多数用例都非常有效,但现在我需要将其与泛型类