Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito returnsFirstArg() to use

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...)

like image 343
Gep Avatar asked Apr 26 '17 16:04

Gep


Video Answer


2 Answers

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]);
like image 193
Mureinik Avatar answered Sep 28 '22 15:09

Mureinik


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));

AnswerPipeline class

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));
    }
}
like image 32
holi-java Avatar answered Sep 28 '22 15:09

holi-java