java Mockito ClassCastException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10324063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 00:34:13  来源:igfitidea点击:

Mockito ClassCastException

javatestingmockingmockito

提问by aces.

The method I want to test has a for loop with logic for each element in bList:

我要测试的方法有一个 for 循环,其中包含 bList 中每个元素的逻辑:

class A {
    void someMethod(){

        for(B b: bList){
            //some logic for b
        }
    }
}

I get an exception when executing following test:

执行以下测试时出现异常:

@RunWith(MockitoJUnitRunner.class)
class ATest {

    @Mock
    private B b;

    @Mock
    private Map<Int, List<B>> bMap;

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private List<B> bList;

    @Spy
    @InjectMocks
    private C c;
    ....

    @Test
    public void test(){

        //this line executes fine
        when(bList.size()).thenReturn(1);

        //strangely this works fine
        when(bMap.get(any())).thenReturn(bList);

        //ClassCastException
        when(bList.get(0)).thenReturn(b); // or when(bList.get(anyInt())).thenReturn(b);

        c.methodIWantToTest();
    }
}

The exception I get is:

我得到的例外是:

java.lang.ClassCastException:
org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ cannot be cast to xyz.B

Has anyone encountered this before and come up with a workaround?

有没有人以前遇到过这个问题并提出了解决方法?

I have searched for a solution and have come across some links: http://code.google.com/p/mockito/issues/detail?id=251and http://code.google.com/p/mockito/issues/detail?id=107

我搜索了一个解决方案并遇到了一些链接:http: //code.google.com/p/mockito/issues/detail? id= 251http://code.google.com/p/mockito/issues /详细信息?id=107

回答by Tim Pote

As this link you postedindicates, you've encountered a bug with Answers.RETURNS_DEEP_STUBS.

正如您发布的此链接所示,您遇到了Answers.RETURNS_DEEP_STUBS.

I don't actually see any reason to actually use RETURNS_DEEP_STUBSin your example code. You really should try to evaluate whether or not you need deep stubs, because, as the Mockito docs say, "every time a mock returns a mock a fairy dies." So if you can, just take that out and your example will work.

我实际上没有看到任何理由RETURNS_DEEP_STUBS在您的示例代码中实际使用。您真的应该尝试评估是否需要深存根,因为正如Mockito 文档所说,“每次模拟返回模拟时,仙女都会死亡。” 所以如果可以的话,把它去掉,你的例子就会起作用。

However, if you insist on using deep stubs, you can hack around this error by up-casting the return value from the method call to Object. For example, replace the offending line in your code with this:

但是,如果您坚持使用深存根,则可以通过将方法调用的返回值向上转换为Object. 例如,将代码中的违规行替换为:

when((Object)bList.get(0)).thenReturn(b);

All that being said, I personally agree with @jhericks. The best solution is probably to use an actual ArrayListwhich contains your mock as opposed to mocking List. The only problem is getting your list injected, so you'd have to use @Spy. For example:

尽管如此,我个人同意@jhericks。最好的解决方案可能是使用ArrayList包含您的 mock的实际而不是 mocking List。唯一的问题是要注入您的列表,因此您必须使用@Spy. 例如:

@RunWith(MockitoJUnitRunner.class)
class ATest{
  private B b = mock(B.class);
  @Spy
  private List<B> bList = new ArrayList<B>() {{ add(b); }};

  @InjectMocks
  private C c = new C();

  @Test
  public void test(){
    c.methodIWantToTest();
    // verify results
  }
}

回答by Leonid Gorshkov

Unfortunately this is not possible

不幸的是这是不可能的

Case: tests on API:

案例:API测试:

interface ConfigurationBuilder {...}
configurationBuilder.newServerAction("s1").withName("111")....create();

Main reason of this usage is compatibility maintenance on compile time. But mockito cannot support generics in chains with RETURNS_MOCKS and RETURNS_DEEP_STUBS options due to type erasure in java:

这种用法的主要原因是编译时的兼容性维护。但是由于 java 中的类型擦除,mockito 不能支持具有 RETURNS_MOCKS 和 RETURNS_DEEP_STUBS 选项的链中的泛型:

Builder/*<ServerActionBuilder>-erasured generic*/ b = configurationBuilder.newServerAction("s1");
b.withName("111")...create();

Result in example above should be ServerAction but in mockito it is Object of generated class.

上面例子中的结果应该是 ServerAction 但在 mockito 中它是生成的类的对象。

see Issue: Can not Return deep stubs from generic method that returns generic type #484

请参阅问题:无法从返回泛型类型的泛型方法中返回深层存根 #484