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


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.