Приклад аргументу MockitoCaptor


141

Може хто-небудь, будь ласка, надати мені приклад, який показує, як користуватися org.mockito.ArgumentCaptorкласом і чим він відрізняється від простих математиків , які надаються mockito.

Я читаю надані макетні документи, але ті не пояснюють це чітко, жоден з них не в змозі пояснити це чітко.

Відповіді:


187

Я згоден з тим, що сказав @fge, більше. Розглянемо приклад. Подумайте, у вас є метод:

class A {
    public void foo(OtherClass other) {
        SomeData data = new SomeData("Some inner data");
        other.doSomething(data);
    }
}

Тепер, якщо ви хочете перевірити внутрішні дані, ви можете використовувати captor:

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

Якщо doSomething(data)мутує innerData, то чи буде ця зміна присутня в assertEquals("Some inner data", actual.innerData), або вона innerDataбуде зафіксована як є, перш ніж doSomething буде виконано?
Cory Klein

@CoryKlein Це OtherClassзнущання, і як це визначено зараз doSomething(), фактично нічого не робитиме, він просто записує об'єкт, який був переданий. Це означає, що він буде зафіксований таким, яким він є до того, як doSomethingбуде виконаний.
Слава Шпитальний

3
В verify, times(1)є за замовчуванням і може бути пропущено.
Інего

як ArgumentCaptor знає, що foo (інше) сталося з моменту його отримання лише після виклику foo (other)?
AvramPop

1
@AvramPop той, хто це знає, - це макетний об’єкт. В ньому міститься багато інформації про макет. Всередині цієї інформації він також містить історію викликів для кожного методу з його параметрами. Коли ви викликаєте verifyметод, він використовує цю інформацію для запуску матчів проти перевірки, яку ви робите. Для кожного параметра він запитує, чи відповідає він певному виклику, який він перевіряє. Коли параметр ArgumentCaptor встановлений, він просто зберігає значення, на які він викликав, і коли він verifyзакінчується, він містить усі відповідні виклики. Це приблизно, як це працює. Сподіваюся, що це допомагає
Слава Шпитальний

35

Дві основні відмінності:

  • коли ви зафіксуєте навіть один аргумент, ви зможете зробити набагато більш детальні тести на цьому аргументі і з більш очевидним кодом;
  • ArgumentCaptorможе захопити більше ніж один раз.

Для ілюстрації останнього скажіть, що у вас є:

final ArgumentCaptor<Foo> captor = ArgumentCaptor.forClass(Foo.class);

verify(x, times(4)).someMethod(captor.capture()); // for instance

Тоді викрадач зможе надати вам доступ до всіх 4 аргументів, на яких ви зможете виконувати твердження окремо.

Ця чи будь-яка кількість аргументів насправді, оскільки a VerificationModeне обмежується фіксованою кількістю викликів; у будь-якому випадку, захоплювач надасть вам доступ до всіх них, якщо бажаєте.

Це також має перевагу в тому, що такі тести (imho) написати набагато простіше, ніж потрібно реалізовувати власні ArgumentMatchers - особливо, якщо ви поєднуєте mockito з assrtj.

О, і, будь ласка, подумайте про те, щоб використовувати TestNG замість JUnit.


1
Що робити, якщо в метод передано кілька параметрів - всі різні типи? Як ви фактично переконаєтесь, що булевий параметр був істинним , наприклад.
ІгорГанапольський

21
Чи можете ви надати пояснення для свого коментаря: О, і, будь ласка, подумайте про використання TestNG замість JUnit. . Навіщо вважати це? Навіщо змінюватись?
Navigatron

1
@IgorGanapolsky ви просто додаєте ще одного ArgumentCaptor. ArgumentCaptor <BigDecimal> arg = ArgumentCaptor.forClass (BigDecimal.class); ArgumentCaptor <String> arg2 = ArgumentCaptor.forClass (String.class); Майкл Майкл = новий Майкл (); michael.sayHi (j); verify (j) .saySomething (arg.capture (), arg2.capture ()); System.out.println ("значення дорівнює" + arg.getValue ()); System.out.println ("рядок є" + arg2.getValue ());
johnwick0831

12

Крок для повного перевірки:

Підготуйте захоплювач:

ArgumentCaptor<SomeArgumentClass> someArgumentCaptor = ArgumentCaptor.forClass(SomeArgumentClass.class);

Перевірте, чи є виклик залежним від компонента (співпрацівником досліджуваного) часом (1), значенням за замовчуванням, тому не потрібно його додавати.

verify(dependentOnComponent, times(1)).send(someArgumentCaptor.capture());

Передайте аргумент передається співпрацівнику

SomeArgumentClass someArgument = messageCaptor.getValue();

деякі аргументи можуть бути використані для тверджень


-2

Тут я наводжу належний приклад одного методу зворотного виклику. тож припустимо, у нас є такий метод, як метод 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)

1
Чи не має він посилатися на ArgumentCaptor?
Феліпе Мартінс Мело

так, ми захоплюємо слухача, переданого методу login (), наприклад, login (LoginProvider loginProvider, LoginListener callback)
Vikram singh

Де captorвизначено у вашій відповіді?
tom_mai78101

ArgumentCaptor <LoginListener> listenerCaptor = ArgumentCaptor.forClass (LoginListener.class);
Vikram singh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.