在方法内部使用Mockito模拟对象

3

我正在编写一个测试,以验证当从SOAP服务接收到不同响应时我的类的行为。我使用Jaxb,因此我的响应包含JaxbElements,对于其中的许多元素,我需要编写模拟程序,如下所示:

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,没有任何业务行为,因此您不应该模拟它们... - Timothy Truckle
因为构建它们需要其他对象(Qname名称、Class<T>声明类型、范围类、T值),而且会影响可读性。无论如何,我可以这样做,但是我遇到了这个异常,我想要理解它。 - marco
2个回答

3

在模拟时涉及到一些额外的泛型操作时,最好使用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<T> mock = mock(jaxbElementClass) ,然后在return响应中使用完整的方法。

你应该首先单独创建这些响应,然后在return中使用它们。

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

尝试一下,它会起作用。

1
我仍然不明白为什么,但是没错,它可以工作!谢谢! - marco
请参考提示#3。如果已完成,则在“thenReturn”指令之前存根另一个模拟的行为。 - Dhawal Kapil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接