Мокіто. Перевірка аргументів методу


220

Я з цим погукував, але не знайшов нічого релевантного. У мене щось подібне:

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj )).thenReturn(null);

Testeable testableObj = new Testeable();
testableObj.setMockeable(mock);
command.runtestmethod();

Тепер я хочу переконатися, що те mymethod(Object o), що називається всередині runtestmethod(), називалося об'єктом o, а не будь-яким іншим. Але я завжди проходжу тест, що б я не ставлю на перевірку, наприклад, з:

Mockito.verify(mock.mymethod(Mockito.eq(obj)));

або

Mockito.verify(mock.mymethod(Mockito.eq(null)));

або

Mockito.verify(mock.mymethod(Mockito.eq("something_else")));

Я завжди проходжу тест. Як я можу виконати цю перевірку (якщо можливо)?

Дякую.

Відповіді:


334

Альтернативою ArgumentMatcherє ArgumentCaptor.

Офіційний приклад:

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());

Captor можна також визначити, використовуючи примітку @Captor :

@Captor ArgumentCaptor<Person> captor;
//... MockitoAnnotations.initMocks(this);
@Test public void test() {
    //...
    verify(mock).doSomething(captor.capture());
    assertEquals("John", captor.getValue().getName());
}

1
Дякуємо за зразок! Ніколи не використовував. Здається, трохи дивно, якщо в коді є такі речі, як Captor , але це допомогло.
Артеміда

1
Ха-ха, я не зрозумів питання, але відповідь мені дуже допомогла. Спасибі :-)
Маркус К.

13
Важливо: підтвердити () / захопити () дзвінок після використання макета. Я думав, що його треба "встановити" раніше ...
Даніель Алдер

1
Дякую за цю відповідь!
Хосе Флавіо Кіспе Іррасабаль

Це чудова відповідь !! Велике спасибі!
Улькі Ігор

61

Ви намагаєтесь зробити логічну рівність, використовуючи метод .equals об'єкта? Ви можете зробити це за допомогою argThat matcher, який включений у Mockito

import static org.mockito.Matchers.argThat

Далі ви можете реалізувати свій власний інструмент відповідності аргументів, який буде відкладати для кожного методу .equals метод

private class ObjectEqualityArgumentMatcher<T> extends ArgumentMatcher<T> {
    T thisObject;

    public ObjectEqualityArgumentMatcher(T thisObject) {
        this.thisObject = thisObject;
    }

    @Override
    public boolean matches(Object argument) {
        return thisObject.equals(argument);
    }
}

Тепер за допомогою коду ви можете оновити його, щоб прочитати ...

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj)).thenReturn(null);

Testeable obj = new Testeable();
obj.setMockeable(mock);
command.runtestmethod();

verify(mock).mymethod(argThat(new ObjectEqualityArgumentMatcher<Object>(obj)));

Якщо ви просто збираєтесь на рівну рівність (той самий об’єкт у пам'яті), просто зробіть це

verify(mock).mymethod(obj);

Це дозволить підтвердити, що воно було викликане один раз.


1
Ви можете використовувати збірку в ReflectionEqualsкласі для цих цілей.
такасот

2
+1 для вашої відповіді. Але я хотів би додати, що verify(mock).mymethod(obj);не перевіряє РІЗНУ рівність (той самий об’єкт у пам'яті). Замість цього він використовує метод equals equals, який можна було б перезаписати.
efux

Ви також можете створити анонімну реалізацію, ArgumentMatcherщоб бути менш багатослівною.
botchniaque

1
Більш докладно: за замовчуванням verify()викликає / вхідний аргумент / equals()метод, а не / записаний об'єкт / equals()метод. це не має значення, якщо ви не намагаєтесь підтвердити, що ваш тест повертає певний екземпляр об'єкта, і суб'єкт повертає те, що повинно бути прозорим декоратором цього екземпляра. В verifyаргументі equals()не знатиме , декоратор; тоді як декоратори equals()будуть переписані, щоб терпіти оригінал. У цьому випадку ваш тест помилково пройде.
Марк МакКенна

54
  • Вам не потрібен відповідник, eqякщо ви не використовуєте інші відповідники.
  • Ви не використовуєте правильний синтаксис - ваш виклик методу повинен бути поза .verify(mock). Зараз ви починаєте перевірку результату виклику методу, не перевіряючи нічого (не здійснюючи виклик методу). Отже всі тести проходять.

Код повинен виглядати так:

Mockito.verify(mock).mymethod(obj);
Mockito.verify(mock).mymethod(null);
Mockito.verify(mock).mymethod("something_else");

Я намагався це раніше, і знову зараз, щоб бути впевненим. У мене ще одна і та ж проблема, тест завжди проходить.
manolowar

2
Це verifeis за посиланням
cnexans

17

argThat плюс лямбда

саме так ви можете провалити перевірку аргументу:

    verify(mock).mymethod(argThat(
      (x)->false
    ));

де

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

argThat плюс стверджує

вищевказаний тест "скаже" Expected: lambda$... Was: YourClass.toSting.... Ви можете отримати більш конкретну причину відмови, якщо використовувати твердження в лямбда:

    verify(mock).mymethod(argThat( x -> {
      assertThat(x).isNotNull();
      assertThat(x.description).contains("KEY");
      return true;
    }));

АЛЕ: ЦЕ ТІЛЬКИ РОБОТИ З 1 МЕТОДИЧНИМ ЗАВДАННЯМ. Якщо перевірений метод називається 2+ разів, мокіто передає всі викликані комбінації кожному верифікатору. Таким чином, mockito очікує, що ваш перевіряючий мовчки повернеться trueза одним із наборів аргументів, та false(без затвердження винятків) для інших дійсних викликів. Це очікування не є проблемою для 1 виклику методу - він повинен просто повернути справжній 1 раз.

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

Тепер тест говорить: Expected: Obj.description to contain 'KEY'. Was: 'Actual description'. ПРИМІТКА: Я використовував assertJтвердження, але саме ви визначаєте, яку структуру тверджень використовувати.


argThat з кількома аргументами.

Якщо ви використовуєте argThat, всі аргументи повинні бути забезпечені збігами. Наприклад:

    verify(mock).mymethod(eq("VALUE_1"), argThat((x)->false));
    // above is correct as eq() is also an argument matcher.

verify(mock).mymethod("VALUE_1", argThat((x)->false));

// above is incorrect; an exceptoin will be thrown, as the fist arg. is given without an argument matcher.

де:

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;

eq матч

найпростіший спосіб перевірити, чи аргумент рівний:

verify(mock).mymethod(eq(expectedValue));
// NOTE:   ^ where the parentheses must be closed.

прямий аргумент

якщо порівняння за посиланням прийнятне, продовжуйте:

verify(mock).mymethod(expectedArg);
// NOTE:   ^ where the parentheses must be closed.

Першопричина початкового відмови питання була в те місце з paranthes: verify(mock.mymethod.... Це було неправильно. Право було б:verify(mock).*


1
Ця моя улюблена відповідь, працює і набагато елегантніше, ніж інші.
Airwavezx

11

Я використовував Mockito.verify таким чином

@UnitTest
public class JUnitServiceTest
{
    @Mock
    private MyCustomService myCustomService;


    @Test
    public void testVerifyMethod()
    {
       Mockito.verify(myCustomService, Mockito.never()).mymethod(parameters); // method will never call (an alternative can be pick to use times(0))
       Mockito.verify(myCustomService, Mockito.times(2)).mymethod(parameters); // method will call for 2 times
       Mockito.verify(myCustomService, Mockito.atLeastOnce()).mymethod(parameters); // method will call atleast 1 time
       Mockito.verify(myCustomService, Mockito.atLeast(2)).mymethod(parameters); // method will call atleast 2 times
       Mockito.verify(myCustomService, Mockito.atMost(3)).mymethod(parameters); // method will call at most 3 times
       Mockito.verify(myCustomService, Mockito.only()).mymethod(parameters); //   no other method called except this
    }
}

5

Ви перевірили метод рівнянь для класу, що макерується? Якщо цей повертається завжди правдивим або ви перевіряєте один і той же екземпляр проти того самого екземпляра, і рівний метод не буде перезаписаний (а для цього лише перевіряє посилання), він повертає істинне.


4

Інший метод - використовувати метод org.mockito.internal.matchers.Equals.Equals замість того, щоб переосмислити один:

verify(myMock).myMethod((inputObject)Mockito.argThat(new Equals(inputObjectWanted)));

3

Ви пробували це з тим же () матчем? А саме:

verify(mockObj).someMethod(same(specificInstance));

У мене була така ж проблема. Я спробував це з matcher eq (), а також matche refEq (), але у мене завжди були помилкові позитиви. Коли я використовував один і той же () matcher, тест не вдався, коли аргументи були різними екземплярами і передавались, коли аргументи були одним і тим же екземпляром.


-1

Ви також можете використовувати TypeSafeDiagnosingMatcher

    private Matcher<GetPackagesRequest> expectedPackageRequest(final AvailabilityRequest request) {
    return new TypeSafeDiagnosingMatcher<GetPackagesRequest>() {

        StringBuilder text = new StringBuilder(500);

        @Override
        protected boolean matchesSafely(GetPackagesRequest req, Description desc) {
            String productCode = req.getPackageIds().iterator().next().getValue();
            if (productCode.equals(request.getSupplierProductCode())) {
                text.append("ProductCode not equal! " + productCode + " , " + request.getSupplierProductCode());
                return true;
            }

            text.append(req.toString());
            return false;
        }

        @Override
        public void describeTo(Description d) {
            d.appendText(text.toString());
        }
    };
}

Потім перевірте це виклик:

Mockito.verify(client).getPackages(Mockito.argThat(expectedPackageRequest(request)));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.