I've started using the Mockito AdditionalAnswers#returnsFirstArg
, which is great:
when(myMock.myFunction(anyString())).then(returnsFirstArg());
but I was wondering if there is an easy way to extract the input argument in order to be used for example in a constructor like:
when(myMock.myFunction(anyString())).thenReturn(new MyObject((String)returnsFirstArg()));
(which obviously doesn't work...)
The easiest (only?) approach, IMHO, would be to use the thenAnswer
method, which allows you to not only return a value, but actually execute some code. Java 8 makes this particularly elegant, as you could just use an anonymous lambda:
when(myMock.myFunction(anyString()))
.thenAnswer(i -> new MyObject((String)i.getArguments()[0]);
I think you maybe need a helper class AnswerPipeline
that I will introduce it a moment how to make the test more readable, more expressiveness and more interesting!!!
Note: you can transform any Answer
to AnswerPipeline
by AnswerPipeline#will(Answer)
method, not only returnsFirstArg()
.
THEN using syntax sugar to describe the test, for example:
Function<String, String> function = mock(Function.class);
when(function.apply(anyString())).then(
/**/ will(returnsFirstArg()) // adapt an Answer to an AnswerPipeline
/**/.as(String.class) // set the result type
/**/.to(String::toUpperCase) // transforming the result
);
assertThat(function.apply("first"), equalTo("FIRST"));
AND then it is easy to solving your problem with no difficulty:
when(myMock.myFunction(anyString()))
.then(will(returnsFirstArg()).as(String.class).to(MyObject::new));
interface AnswerPipeline<T> extends Answer<T> {
static <R> AnswerPipeline<R> will(Answer<R> answer) {
return answer::answer;
}
default <R> AnswerPipeline<R> as(Class<R> type) {
return to(type::cast);
}
default <R> AnswerPipeline<R> to(Function<T, R> mapper) {
return it -> mapper.apply(answer(it));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With