【问题标题】:Mockito mock objects inside a method方法内的 Mockito 模拟对象
【发布时间】:2017-09-26 10:25:18
【问题描述】:

我正在编写一个测试来验证我的类在接收来自 SOAP 服务的不同响应时的行为。 我使用 Jaxb,所以我的回复包含 JaxbElements,对于其中许多,我需要编写一个 mock,如下所示:

JAXBElement<String> mock1 = mock(JAXBElement.class);
when(mock1.getValue()).thenReturn("a StringValue");
when(result.getSomeStringValue()).thenReturn(mock1);

JAXBElement<Integer> mock2 = mock(JAXBElement.class);

when(mock2.getValue()).thenReturn(new Integer(2));
when(result.getSomeIntValue()).thenReturn(mock2);
... <continue>

我想做的就是以这种方式重构这段代码:

when(result.getSomeStringValue())
    .thenReturn(mockWithValue(JAXBElement.class, "a StringValue");

when(result.getSomeIntValue())
    .thenReturn(mockWithValue(JAXBElement.class, 2));

并定义一个方法:

private <T> JAXBElement<T> mockWithValue(Class<JAXBElement> jaxbElementClass, T value) {
    JAXBElement<T> mock = mock(jaxbElementClass);
    when(mock.getValue()).thenReturn(value);
    return mock;
}

当我在重构之前执行代码时,一切正常。 不幸的是,当我在重构后执行代码时,收到此错误:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.mypackage.ResultConverterTest.shouldConvertASuccessfulResponseWithAllTheElements(ResultConverterTest.java:126)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
  1. missing thenReturn()
  2. you are trying to stub a final method, you naughty developer!
  3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

其中第 126 行是mockWithValue 方法的第一次调用。

所以问题是:有没有办法重用相同的代码来创建许多具有相似行为的模拟?

【问题讨论】:

  • 由于 JaxB 生成的类是简单的 DTO,没有任何业务行为,因此您不应模拟它们...
  • 因为构建它们需要其他对象(Qname 名称、Class 声明类型、类范围、T 值)并且它失去了可读性。反正我能做到,但是碰到了这个异常,想了解一下。

标签: java unit-testing mocking mockito


【解决方案1】:

当涉及到一些额外的泛型参与时,最好使用doReturn()..when() 语法:

    doReturn(mockWithValue(JAXBElement.class, "a StringValue"))
        .when(result).getSomeStringValue();

    doReturn(mockWithValue(JAXBElement.class, 2))
        .when(result).getSomeIntegerValue();

    private <T> JAXBElement<T> mockWithValue(Class<JAXBElement> jaxbElementClass, T value) {
        JAXBElement<T> mock = mock(jaxbElementClass);
        doReturn(value).when(mock).getValue();
        return mock;
    }

【讨论】:

    【解决方案2】:

    您不应在创建响应时进行模拟。

    让我解释一下,在这段代码中

    private <T> JAXBElement<T> mockWithValue(Class<JAXBElement> jaxbElementClass, T value) {
        JAXBElement<T> mock = mock(jaxbElementClass);
        when(mock.getValue()).thenReturn(value);
        return mock;
    }
    

    你在嘲笑JAXBElement&lt;T&gt; mock = mock(jaxbElementClass),然后你在return响应中使用了这个完整的方法。

    您应该先分别创建这些响应,然后在 return 中使用它们。

    String stringResponse=mockWithValue(JAXBElement.class, "a StringValue");
    when(result.getSomeStringValue()).thenReturn(stringResponse);
    

    试试这个,它会起作用的。

    【讨论】:

    • 我仍然不明白为什么,但是是的,它有效!谢谢!
    • 另见提示 #3 3:如果完成,您将在 'thenReturn' 指令之前存根内部另一个模拟的行为
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 2017-05-17
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多