Mockito returnsFirstArg () использовать

Я начал использовать Mockito AdditionalAnswers#returnsFirstArg, что здорово:

when(myMock.myFunction(anyString())).then(returnsFirstArg());

но мне было интересно, есть ли простой способ извлечь входной аргумент, чтобы его можно было использовать, например, в конструкторе типа:

when(myMock.myFunction(anyString())).thenReturn(new MyObject((String)returnsFirstArg()));

(который, очевидно, не работает...)

3 ответов


самый простой (единственный?) подход, ИМХО, был бы использовать thenAnswer метод, который позволяет не только возвращать значение, но и фактически выполнять некоторый код. Java 8 делает это особенно элегантным, так как вы можете просто использовать анонимный лямбда:

when(myMock.myFunction(anyString()))
    .thenAnswer(i -> new MyObject((String)i.getArguments()[0]);

Я думаю, что вам, возможно, понадобится вспомогательный класс AnswerPipeline что я введу его момент, как сделать тест более читабельный, больше экспрессивность и интересные!!!

Примечание: вы можете преобразовать любой Answer до AnswerPipeline by AnswerPipeline#will(Answer) метод, не только returnsFirstArg().

затем использование синтаксического сахара для описания теста, например:

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

и затем он легко решить вашу проблему без труда:

when(myMock.myFunction(anyString()))
           .then(will(returnsFirstArg()).as(String.class).to(MyObject::new));

класс AnswerPipeline

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

можно использовать thenAnswer метод и создать Answer чтобы получить аргумент:

when(myMock.myFunction(anyString())).thenAnswer(new Answer<MyObject>() {
    @Override
    public MyObject answer(InvocationOnMock invocation) throws Throwable {
        String s = invocation.getArgument(0); // get first argument
        return new MyObject(s);
    }
});

если вы используете Java 8, вы можете использовать лямбда-синтаксис:

when(myMock.myFunction(anyString()))
  .thenAnswer(args -> new MyObject(args.getArgument(0)));

Примечания:

  • мне не нужно invocation.getArgument(0) до String, но в зависимости от вашей версии java / mockito, возможно, это будет необходимо:(String) invocation.getArgument(0)
  • в зависимости от вашей версии mockito,getArgument(int) метод может не существовать, и вы должны использовать (в в этом случае, вызов будет getArgumentAt(0, String.class)). Или вы можете использовать getArguments()[0] и String