ClassCastException在使用Mockito模拟泛型类型时 [英] ClassCastException when mocking generic type using Mockito

查看:621
本文介绍了ClassCastException在使用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());
}
卡车


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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆