Reputation: 681
I am writing a test for verifying the behavior of my class when receiving different responses from a SOAP Service.
I use Jaxb, so my response contains JaxbElements
, and for many of them, I need to write a mock, like that:
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>
what I would like to do, is refactorize this code that way:
when(result.getSomeStringValue())
.thenReturn(mockWithValue(JAXBElement.class, "a StringValue");
when(result.getSomeIntValue())
.thenReturn(mockWithValue(JAXBElement.class, 2));
and define a method:
private <T> JAXBElement<T> mockWithValue(Class<JAXBElement> jaxbElementClass, T value) {
JAXBElement<T> mock = mock(jaxbElementClass);
when(mock.getValue()).thenReturn(value);
return mock;
}
when I execute the code before the refactoring everything works properly. Unfortunately, when I execute the the code after the refactoring, I receive this error:
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
where line 126 is the first invocation of the mockWithValue
method.
So the question is: is there a way to reuse the same code in order to create many mocks with similar behavior?
Upvotes: 3
Views: 4356
Reputation: 26572
When it comes to some additional generics involvement while mocking it is better to go for the doReturn()..when()
syntax:
doReturn(mockWithValue(JAXBElement.class, "a StringValue"))
.when(result).getSomeStringValue();
doReturn(mockWithValue(JAXBElement.class, 2))
.when(result).getSomeIntegerValue();
and
private <T> JAXBElement<T> mockWithValue(Class<JAXBElement> jaxbElementClass, T value) {
JAXBElement<T> mock = mock(jaxbElementClass);
doReturn(value).when(mock).getValue();
return mock;
}
Upvotes: 3
Reputation: 2767
You should not mock while creating response.
Let me explain, in this code
private <T> JAXBElement<T> mockWithValue(Class<JAXBElement> jaxbElementClass, T value) {
JAXBElement<T> mock = mock(jaxbElementClass);
when(mock.getValue()).thenReturn(value);
return mock;
}
you are mocking JAXBElement<T> mock = mock(jaxbElementClass)
and then you are using this complete method in return
response.
You should first created these responses separately and then use them inside return
.
String stringResponse=mockWithValue(JAXBElement.class, "a StringValue");
when(result.getSomeStringValue()).thenReturn(stringResponse);
Try this, it will work.
Upvotes: 2