Як перевірити декілька викликів методів з різними параметрами


116

У мене є такий метод, на якому я хочу перевірити поведінку.

public void methodToTest(Exception e, ActionErrors errors) {
    ...

    errors.add("exception.message", 
            ActionMessageFactory.createErrorMessage(e.toString()));

    errors.add("exception.detail",
            ActionMessageFactory.createErrorMessage(e.getStackTrace()[0].toString()));

    ...
}

У моєму класі @Test я сподівався зробити щось подібне, щоб перевірити, що errors.add()викликається "izuzet.message" і знову "izjem.detail"

verify(errors).add(eq("exception.message"), any(ActionError.class));
verify(errors).add(eq("exception.detail"), any(ActionError.class));

проте Мокіто скаржиться так

Argument(s) are different! Wanted:
actionErrors.add(
    "exception.message",
    <any>
);

Actual invocation has different arguments:
actionErrors.add(
    "exception.detail",
    org.apache.struts.action.ActionError@38063806
);

Як я можу сказати Mockito перевірити обидва значення?


1
якщо у вас є два способи з різними підписами, ви можете написати окремий тестовий випадок для обох.
Naveen Babu

8
Так, але в цьому випадку це той самий метод підпису, але просто різні значення аргументу
Бред

ви можете спробувати скористатисяMockito.reset()
taccsot

Відповіді:


102

Подальше читання змусило мене спробувати використовувати ArgumentCaptors та наступні роботи, хоча набагато більш багатослівні, ніж я хотів би.

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);

verify(errors, atLeastOnce()).add(argument.capture(), any(ActionMessage.class));

List<String> values = argument.getAllValues();

assertTrue(values.contains("exception.message"));
assertTrue(values.contains("exception.detail"));

чи є спосіб переконатися, що певні параметри були сполучені за допомогою цього підходу? Скажімо, наприклад , метод Ора мав два аргументи і хотів переконатися , що вони були названі разом
committedandroider

1
Тестовий випадок ОП викликає methodToTest()рівно один раз, тому ця відповідь підтверджує, що два дзвінки здійснюються разом. Захоплений List<String> values, який стверджується, буде містити лише два значення, які тестуються, і жодне інше. Ви також можете додати assertTrue(values.size == 2). Якщо ви цього хочете, я б замінив 3 заяви assrtTrue одним Hamcrest ...assertThat(values, contains("exception.message", "exception.detail"));
Бред

чи не є метод виклику тестового випадку OPTToTest () двічі?
відданий

вибачте, що я не зрозуміла. Я мав на увазі сценарій, коли ОП хотів перевірити, що два аргументи були викликані спільно. Таким чином, підпис методу виглядатиме приблизно як public void methodToTest (виняток e, повідомлення m, помилки ActionErrors) {так що конкретний виняток викликається певним повідомленням. Я думав , що ви могли б просто мати два ArgumentCaptors , а потім отримати індекс і порівняти з використанням значень на цих індексів в обох списках значень
committedandroider

Тестовий випадок OP дзвонить methodToTest()один раз. Саме аргумент методу ActionErrors errorsвнутрішньо викликається двічі.
Бред

61

Якщо порядок обох add()дзвінків є релевантним, ви можете використовувати InOrder:

InOrder inOrder = inOrder(errors);
inOrder.verify(errors).add(eq("exception.message"), any(ActionError.class));
inOrder.verify(errors).add(eq("exception.detail"), any(ActionError.class));

7
Досить передати єдиний errorsаргумент: InOrder inOrder = inOrder(errors);(див. Документи )
GreenhouseVeg

2
Що робити, якщо замовлення НЕ актуально? що часто буває.
haelix

1
@haelix У цьому випадку використовуйте відповідь Бредса. Перетворити Listв Setі стверджують , що набір входів одно безліч , що задається аргументом захопленнями.
flopshot

25

Спробуйте щось подібне:

verify(errors, times(2))
     .add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
          any(ActionError.class));

4
Ваш чек, очевидно, занадто розслаблений.
гелікс

17

у вас, ймовірно, є проблема в коді. Тому що фактично ви пишете цей код:

Map<Character, String> map = mock(Map.class);

map.put('a', "a");
map.put('b', "b");
map.put('c', "c");

verify(map).put(eq('c'), anyString());
verify(map).put(eq('a'), anyString());
verify(map).put(eq('b'), anyString());

Зауважте, що перша перевірка навіть не в порядку фактичних викликів.

Крім того, я б рекомендував вам насправді не знущатися над типом, яким ви не володієте, наприклад, типу struts.

[EDIT @Brad]

Після запуску коду Бріса (вище) в моєму IDE я бачу, що я використовував ActionError замість ActionMessage, тому моя перевірка () не відповідала. Повідомлення про помилку, яке я спочатку опублікував, вводило мене в оману, думаючи, що це перший аргумент, який не відповідає. Виявляється, це був другий аргумент.

Тож відповідь на моє запитання така

/** 
 * note that ActionMessageFactory.createErrorMessage() returns ActionMessage
 * and ActionError extends ActionMessage
 */
verify(errors).add(eq("exception.message"), any(ActionMessage.class));
verify(errors).add(eq("exception.detail"), any(ActionMessage.class));

1
Не розумійте, що ви намагаєтесь сказати. Чи має значення порядок перевірки? якщо наказ про підтвердження має значення. Чому тоді тут надається InOrder api?
Олександр Папченко

Так само, як те, що написано вище, підтвердження порядку не має значення; ось чому є InOrder.
Бріс

12

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

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));

1

1) Скажіть Мокіто загальне очікування дзвінків.

2) Скажіть Мокіто, скільки разів очікувалося кожне поєднання параметрів.

verify(errors, times(2)).add(any(), any(ActionMessage.class));

verify(errors, atLeastOnce()).add(eq("exception.message"), any());
verify(errors, atLeastOnce()).add(eq("exception.detail"), any());

0

Аналогічно до @ sendon1928 ми можемо використовувати:

Mockito.times(wantedInvocationCount)

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

Mockito.verifyNoMoreInteractions(mock)

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

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(2));

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