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