Вопрос по java, call, mockito, verify – Я попытался показать, как граф классов будет обрабатываться с помощью Person-Address в примере. Вам понадобится конструктор для каждого класса в дереве (но, возможно, они могут быть созданы по мере необходимости, но не все сразу). Конечно, если ваш граф классов данных состоит из сотен классов, то это может быть не лучшим подходом.

2

я есть немного логики, которая должна быть проверена, например:

{
    ...
    A.add("1");
    ...
    A.add("what ever");
    ...
    A.add("2");
    A.delete("5");
    ...
}

Я уже сменил A в моем тесте, и я могу проверить, что метод add вызывается один раз для аргумента ("2"), например:

Mockito.verify(mockedA).add("2");

У меня вопрос, как я могу проверить, могу ли я проверить, что последний вызов метода add - это add ("2") вместо других аргументов.

Так как тест выше не может поймать, если кто-то случайно добавил другой вызов, такой как add ("3") в последнем. Пожалуйста, обратите внимание, что мы не заботимся о других вызовах методов на A после этого. Мы также не заботимся о временах вызываемого метода, последовательности вызываемых методов.Ключевым моментом здесь является то, можем ли мы проверить последний истинный аргумент для определенного метода определенного mockedObject.

Если вы спросите, зачем вам такая функциональность, я бы сказал, что в реальном мире нам, возможно, понадобится справиться с некоторой логикой, которая задает что-то, и последний набор выигрывает, и чтобы кто-то случайно не установил другую неожиданную вещь, и я бы хотел бы использовать наши UT, чтобы поймать это. И чтобы не сделать тест слишком сложным и аккуратным, я ожидаю только проверки последнего вызова определенного метода объекта, а не проверки чего-то вроде order / noMoreInteractions / AtMostTimes и так далее.

Спасибо, это очень полезно. hongchangfirst
Смотрите <stackoverflow.com/questions/8504074/...> Может быть, вы найдете это полезным. staszko032

Ваш Ответ

3   ответа
0

что вы издеваетесь над классом данных. По моему опыту лучше оставить (с состоянием) классы данных и фиктивные (без состояния) сервисы. Таким образом, вы можете проверить, что тестируемый метод производит правильные данные, а не просто проверять серию вызовов. Наряду со сборщиками тестовых данных (что упрощает создание экземпляров ваших классов данных с некоторым состоянием по умолчанию, например, с использованием шаблона построителя), становится действительно легко писать тесты.

Если вам нужно издеваться, единственный способ проверить, что вы хотите, это использоватьInOrderи проверьте каждый из вызовов на макете и завершитеverifyNoMoreInteractions.

Я попытался показать, как граф классов будет обрабатываться с помощью Person-Address в примере. Вам понадобится конструктор для каждого класса в дереве (но, возможно, они могут быть созданы по мере необходимости, но не все сразу). Конечно, если ваш граф классов данных состоит из сотен классов, то это может быть не лучшим подходом. Tobb
Я думал об использовании реального объекта вместо смоделированного, чтобы проверить последнее состояние, которое у нас есть. Это неплохая идея. Когда урок тривиален, это прекрасно. Хотя, если класс делегирует это другому классу, и этот класс также делегирует другим классам, будучи сложным и имеющим много зависимостей, это сделать нелегко. А также это больше похоже на тестирование логики A вместо тестирования логики использования A. hongchangfirst
Рассмотрим такой случай: что если ваш класс делегирует это другому классу, и этот класс также делегирует другим классам, будучи сложным, имеющим много зависимостей? hongchangfirst
Создание этих сборщиков - это немного работы, но как только они у вас есть, написание тестов с их использованием становится действительно приятным. Гораздо проще проверить состояние, чем проверить несколько вызовов методов. Tobb
Ваш тест немного «расширится», это правильно. Но обычно классы данных довольно просты. Использование шаблона компоновщика также может уменьшить некоторые сложности, я успешно использовал их в прошлом. Если ваш класс данных являетсяPersonи вы просто хотите человека по умолчанию, вы делаетеnew PersonBuilder().build();, Тогда вы получите человека по имени "Test Testman" или что-то в этом роде. Если вы хотите переопределить некоторые значения для вашего конкретного теста, вы делаете что-то вродеnew PersonBuilder().firstName("Donald").lastName("Duck").address(new AddressBuilder().city("Duckburg").build()).build(); Tobb
4

О порядке вызовов

По умолчанию,Mockito.verify() не имеет значения порядка вызова.
Чтобы принять это во внимание, заверните макет вInOrder экземпляр и выполнить проверку вызова на этом экземпляре.

О не более

Если макет больше не вызывается после методов, которые вы хотите проверить, вы можете использоватьMockito.verifyNoMoreInteractions(Object... mocks) который проверяет, имеет ли какое-либо из заданных макетов непроверенное взаимодействие, такое как:

InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verifyNoMoreInteractions(mockedA);

Если макет все еще может быть вызван после методов, которые вы хотите проверить, вы можете добавить после того, как ваш проверяет вызовverify(T mock, VerificationMode mode) передаваяVerificationMode который проверяет, что было выполнено максимум 2 вызова.

InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verify(mockedA, Mockito.atMost(2)).add(Mockito.anyString());

Предупреждение о вашей мысли и этот способ издеваться

Так как тест выше не может поймать, если кто-то случайно добавил другой вызов, такой как add ("3") в последнем.

Mockito предоставляет мощный и широкий инструментарий для работы с макетами. Некоторые функции, такие как проверка и, в частности, проверка того, что больше не было обнаружено взаимодействия о макете или конкретном методе макетасделать ваш тест более сложным для чтения и поддержания.
Кроме того, в настоящее время вы хотите проверить, что вызовы на макете были выполнены в определенном порядке. Но вы, как правило, хотите использовать эти проверки только по мере необходимости в соответствии с бизнес / логическими сценариями, а не с техническими вызовами.
Предположив, например, что в тестируемом методе у вас есть случай, когда по бизнес-причинам мошеный метод вызывается 3 раза, а другой случай, когда мошенливый метод вызывают дважды. Возможно, имеет смысл проверить, что он вызывается только 2 раза, а не больше в случае двух ожидаемых вызовов.
Но в целом вы должны быть осторожны, чтобы ваш модульный тест не злоупотреблял проверкой проверки, которая может выглядеть как утверждение в описании потока, а не утверждение в отношении поведения / логики.

@hongchangfirst ОК. Я уточнил, чтобы различать два случая. davidxxx
@hongchangfirst Хорошо. Я понимаю вашу точку зрения. Я обновился, но мне действительно интересно, имеет ли смысл добавлять такую ​​сложность в тест. Я добавляю последнее замечание о том, что я думаю об этом. davidxxx
Это не работает, поскольку логика может вызывать другие методы, такие как A.delete () для A, ключевым моментом здесь является проверка последнего истинного аргумента для определенного МЕТОДА объекта. hongchangfirst
Благодарю. в то время как это все еще не то, что мы ожидаем. Что если метод add вызывается более двух раз? Ключевым моментом является то, можем ли мы проверить последний вызов определенного метода объекта? hongchangfirst
Как я хочу избежать сложности, так я хотел бы иметь такую ​​функциональность. В большинстве случаев сейчас может работать, но он не может поймать, если кто-то переместить первый вызов на последний. Ваш UT проходит, но ваш сервис прерывается. Или вы можете утверждать, что мы можем использовать inOrder для проверки последовательности. Но я бы сказал, что если кто-то удалит первый, а метод все еще не сломан. Но твой UT ломается. В целом, это не то, что мы ожидаем. hongchangfirst
2

вдохновленному ArgumentCaptor, вместо getAllValues ​​и проверки последовательности мы можем использовать getValue из captor, поскольку getValue из captor всегда получает последний истинный аргумент. Мы можем сделать это так:

    ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
    Mockito.verify(mockedA, Mockito.atLeastOnce()).add(captor.capture());
    Assert.assertEquals("2", captor.getValue());

Похожие вопросы