【问题标题】:Mockito ClassCastExceptionMockito ClassCastException
【发布时间】:2012-04-25 21:27:03
【问题描述】:

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

class A {
    void someMethod(){

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

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

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

我得到的例外是:

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

有没有人遇到过这种情况并想出解决方法?

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

【问题讨论】:

  • 这可能是链接中指出的现有问题。
  • 你真的想模拟 List 和 Map 还是只是为了说明问题?为什么不直接使用 ArrayList 和 HashMap 实现并注入它们?
  • @jhericks 是的,你是对的,我应该切换到使用 ArrayList 和 HashMap 实现。谢谢

标签: java testing mocking mockito


【解决方案1】:

正如this link you posted 所指出的,您遇到了Answers.RETURNS_DEEP_STUBS 的错误。

我实际上没有看到在您的示例代码中实际使用 RETURNS_DEEP_STUBS 的任何理由。您确实应该尝试评估是否需要深度存根,因为正如Mockito docs say 一样,“每次模拟返回模拟时,仙女就会死去。”所以如果可以的话,把它拿出来,你的例子就会奏效。

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

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

话虽如此,我个人同意@jhericks。最好的解决方案可能是使用包含您的模拟的实际ArrayList,而不是模拟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
  }
}

【讨论】:

  • 我尝试了两种替代方法,它们都有效。我看到了 Mockito 文档中所述的情况,并将避免使用模拟来返回模拟。谢谢。
【解决方案2】:

很遗憾,这是不可能的

案例:API 测试:

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

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

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

上面示例中的结果应该是 ServerAction,但在 mockito 中它是生成类的 Object。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多