Пример для Mockito argumentCaptor
Может ли кто-нибудь указать мне пример, показывающий, что используется класс org.mockito.ArgumentCaptor
и как он отличается от простых совпадений, которые предоставляются с mockito.
Я прочитал предоставленные документы mockito, но это не ясно иллюстрирует это,
ни они не могут объяснить это с ясностью.
Ответы
Ответ 1
Я согласен с тем, что сказал @fge, более того. Давайте посмотрим на пример.
У вас есть метод:
class A {
public void foo(OtherClass other) {
SomeData data = new SomeData("Some inner data");
other.doSomething(data);
}
}
Теперь, если вы хотите проверить внутренние данные, вы можете использовать захват:
// Create a mock of the OtherClass
OtherClass other = mock(OtherClass.class);
// Run the foo method with the mock
new A().foo(other);
// Capture the argument of the doSomething function
ArgumentCaptor<SomeData> captor = ArgumentCaptor.forClass(SomeData.class);
verify(other, times(1)).doSomething(captor.capture());
// Assert the argument
SomeData actual = captor.getValue();
assertEquals("Some inner data", actual.innerData);
Ответ 2
Два основных отличия:
- когда вы фиксируете хотя бы один аргумент, вы можете сделать гораздо более сложные тесты по этому аргументу и с более очевидным кодом;
- a
ArgumentCaptor
может захватывать не один раз.
Чтобы проиллюстрировать последнее, скажем, что у вас есть:
final ArgumentCaptor<Foo> captor = ArgumentCaptor.forClass(Foo.class);
verify(x, times(4)).someMethod(captor.capture()); // for instance
Затем уловщик сможет предоставить вам доступ ко всем 4 аргументам, которые вы затем можете выполнять отдельно.
Это или любое количество аргументов на самом деле, так как a VerificationMode
не ограничено фиксированным числом вызовов; в любом случае, захватчик предоставит вам доступ ко всем из них, если хотите.
Это также имеет то преимущество, что такие тесты (imho) намного проще писать, чем реализовать собственный ArgumentMatcher
- особенно если вы комбинируете mockito с assertj.
О, и, пожалуйста, рассмотрите возможность использования TestNG вместо JUnit.
Ответ 3
Рассмотрим сценарий, в котором мы тестируем метод, который зависит от сотрудника. Этот сотрудник принимает аргумент при вызове одного из его методов. Теперь их может быть два scenarios-
1. Аргумент передается извне тестируемому методу, а затем используется соавтором во время вызова его собственного метода.
method(argument arg)
{
collaborator.callMethod(arg);
}
Чтобы проверить этот метод, мы издеваемся над соавтором, а затем вызываем метод следующим образом
method(arg1);
Mockito.verify(collaborator).callMethod(arg1);
Таким образом, здесь, в методе тестирования, у нас есть экземпляр arg1 и, следовательно, можно проверить
2. Аргумент, используемый коллаборатором для вызова собственного метода, не передается извне, а создается внутри тестируемого метода.
method()
{
arg = CreateArgumentInternally();
collaborator.callMethod(arg);
}
Чтобы проверить этот метод, мы издеваемся над соавтором, а затем вызываем метод следующим образом
method();
Но как мы можем проверить, с каким аргументом вызывался соавтор, поскольку у нас нет доступа к аргументу, так как он был создан внутри метода. Это где Mockito ArgumentCaptor входит в картину.
Используя ArgumentCaptor, мы можем получить экземпляр аргумента, созданный внутри и использованный в вызове коллаборатора, и, таким образом, мы можем проверить его.
Mockito.verify(collaborator).callMethod(captor.capture());
Argument actual = captor.getValue();
Reference- Понимание Mockito ArgumentCaptor с помощью примера теста Spring Boot
Ответ 4
Шаги для полной проверки:
Подготовьте похитителя:
ArgumentCaptor<SomeArgumentClass> someArgumentCaptor = ArgumentCaptor.forClass(SomeArgumentClass.class);
проверьте, что вызовы, зависящие от компонента (участника тестируемого субъекта) times (1), являются значением по умолчанию, поэтому их не нужно добавлять.
verify(dependentOnComponent, times(1)).send(someArgumentCaptor.capture());
Получить аргумент, переданный сотруднику
SomeArgumentClass someArgument = messageCaptor.getValue();
someArgument может использоваться для утверждений
Ответ 5
Здесь я приведу вам пример одного метода обратного вызова. поэтому предположим, что у нас есть метод, подобный методу login():
public void login() {
loginService = new LoginService();
loginService.login(loginProvider, new LoginListener() {
@Override
public void onLoginSuccess() {
loginService.getresult(true);
}
@Override
public void onLoginFaliure() {
loginService.getresult(false);
}
});
System.out.print("@@##### get called");
}
Я также поместил здесь весь вспомогательный класс, чтобы сделать пример более понятным: класс loginService
public class LoginService implements Login.getresult{
public void login(LoginProvider loginProvider,LoginListener callback){
String username = loginProvider.getUsername();
String pwd = loginProvider.getPassword();
if(username != null && pwd != null){
callback.onLoginSuccess();
}else{
callback.onLoginFaliure();
}
}
@Override
public void getresult(boolean value) {
System.out.print("login success"+value);
}}
и у нас есть слушатель LoginListener как:
interface LoginListener {
void onLoginSuccess();
void onLoginFaliure();
}
сейчас я просто хотел протестировать метод login() класса Login
@Test
public void loginTest() throws Exception {
LoginService service = mock(LoginService.class);
LoginProvider provider = mock(LoginProvider.class);
whenNew(LoginProvider.class).withNoArguments().thenReturn(provider);
whenNew(LoginService.class).withNoArguments().thenReturn(service);
when(provider.getPassword()).thenReturn("pwd");
when(provider.getUsername()).thenReturn("username");
login.getLoginDetail("username","password");
verify(provider).setPassword("password");
verify(provider).setUsername("username");
verify(service).login(eq(provider),captor.capture());
LoginListener listener = captor.getValue();
listener.onLoginSuccess();
verify(service).getresult(true);
Также не забудьте добавить аннотацию над тестовым классом как
@RunWith(PowerMockRunner.class)
@PrepareForTest(Login.class)