У меня есть метод, который содержит 2 условия. В каждом условии вызывается метод Logger.error. Первый тест, который проверяет вызов этого метода, преуспевает, но и любой другой тест не пройден сMockito не удалось проверить несколько вызовов методов из org.slf4j.Logger
Wanted, но не применяло ... На самом деле, были нулевые взаимодействий с это макет.
Кто-нибудь знает, почему это происходит?
Ниже я представил пример класса и модульный тест, который будет генерировать вопрос:
package packageName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class X {
private static final Logger LOGGER = LoggerFactory.getLogger(X.class);
public void execute(boolean handle1stCase) {
if (handle1stCase) {
LOGGER.error("rumpampam");
} else {
LOGGER.error("latida");
}
}
}
Тест:
package packageName;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
@RunWith(PowerMockRunner.class)
@PrepareForTest({LoggerFactory.class})
public class XTest {
@Mock
private Logger loggerMock;
private X x;
@Before
public void construct() {
MockitoAnnotations.initMocks(this);
mockStatic(LoggerFactory.class);
when(LoggerFactory.getLogger(any(Class.class))).thenReturn(loggerMock);
x = new X();
}
@Test
public void whenFirstCaseErrorLogged() throws Exception {
x.execute(true);
verify(loggerMock, times(1)).error("rumpampam");
}
@Test
public void whenSecondCaseErrorLogged() throws Exception {
x.execute(false);
verify(loggerMock, times(1)).error("latida");
}
}
Результат:
Требуются, но не вызывается: loggerMock.error ("latida"); -> в пакетеName.XTest.whenSecondCaseErrorLogged (XTest.java:51)
На самом деле было нулевое взаимодействие с этим макетом.
EDIT:
Я дал краткий ответ, почему каждый тест, за исключением 1-го терпел неудачу в comment of this answer.
МОЕ РЕШЕНИЕ ПРОБЛЕМЫ:
В тесте обеспечивают:
public static Logger loggerMockStatic;
чем создать только один экземпляр для всех тестов и обеспечить его в статической переменной, и использовать статический loggerMockStatic из чем на. Таким образом, у вас было бы:
...
MockitoAnnotations.initMocks(this);
if (loggerMockStatic == null) {
loggerMockStatic = loggerMock;
}
mockStatic(LoggerFactory.class);
//when(LoggerFactory.getLogger(any(Class.class))).thenReturn(loggerMock);
when(LoggerFactory.getLogger(any(Class.class))).thenReturn(loggerMockStatic);
...
и использовать loggerMockStatic в методах проверки вместо loggerMock.
НЕКОТОРЫЕ МЫСЛИ ОТНОСИТЕЛЬНО ПОДХОД:
Для меня это хорошо, потому что
1. это не нарушает дизайн (если считать, что необходимая переменная должна быть постоянной, чем он будет оставаться таким образом) ,
2. В тест добавлены только 4 строки, которые позволят вам протестировать поведение константы (в данном случае регистратора). Не так много загрязняющих и тестовых случаев по-прежнему ясно.
Метод «удалить окончательный и обеспечить сеттер», как я объяснил в this answer, открывает систему уязвимостям. Нет необходимости кому-то устанавливать регистратор в класс, и мне всегда хотелось бы, чтобы система была открыта по мере необходимости. Не требуется установка сеттера только для необходимости теста. Тест должен работать для реализации, а не наоборот.
В частности, при проверке ведения журнала я не считаю, что регистрация должна быть проверена в целом (в большинстве случаев). Регистрация должна быть аспектом приложения.И когда у вас есть другие выходы для проверки определенного пути, чем те, которые должны быть протестированы. Но в этом случае (и, возможно, другие), где нет другого выхода для определенного пути, такого как ведение журнала и возврат в определенное состояние, требуется проверка журнала (по мне). Я хочу всегда знать, что сообщение журнала останется в журнале, даже если кто-то изменит это условие. Если не было журнала, и если кто-то изменит условие, то не будет никакого способа узнать, что ошибка находится в этом фрагменте кода (за исключением, может быть, отладки).
Я обсуждал с некоторыми коллегами, что наличие отдельного класса для ведения журнала приведет к трюку. Таким образом, константа изолирована в другом классе, и вы сможете проверять поведение только с помощью Mockito. Они сделали еще одно замечание, что таким образом, если вы захотите отправить журнал по электронной почте, было бы легче изменить его.
Прежде всего, я считаю это преждевременной модуляцией, если вы не собираетесь в ближайшем будущем переключаться между способами ведения журнала.
Во-вторых, используя только Mockito +, имеющий еще один класс и + 3 строки кода VS, моя одна строка кода (logger.error (...)) +, используя PowerMockito, я бы снова воспользовался позже. Добавление дополнительных зависимостей во время тестирования не сделает ваш производственный код более медленным и громоздким. Возможно, при рассмотрении вопроса о продолжении интеграции и о том, что тестирование так же важно, как и другие этапы, вы можете сказать, что это сделает процесс медленнее и громоздким при тестировании, но я бы пожертвовал этим - кажется, это не слишком важно для меня.
«В вашем случае вам повезло, и это не происходит, но ... «Что касается удачи, это неправда. Я точно объяснил, почему в комментарии к вашему другому ответу: http://stackoverflow.com/a/20196591/521754 Я бы предложил в будущем не писать несколько ответов, а отредактировать свои старые с комментарием, который был отредактирован. – despot
«Почему вы хотите сделать что-то постоянное, когда оно не постоянное?» Логгер не постоянный ?! Возможно, я ошибаюсь, но он не должен меняться во время выполнения. Разве это не определение константы в java ?! :) «Может ли статический финал помешать вам изменить состояние объекта?» какое состояние вы измените в регистраторе, мне просто любопытно :) (проверьте org.slf4j.Logger и посмотреть, какие методы у него есть;)) – despot
Не нужно было вовлекать адреса памяти в ваш ответ :) этого было бы достаточно: «потому что ваш X :: LOGGER статичен, он не будет повторно инициализирован»;) Никогда тем меньше, я собираюсь принять ваш ответ, потому что 2 абзаца, которые начинаются с «Now let say ...», являются тем же самым комментарием комментария, который я дал вам в вашем предыдущем ответе http://stackoverflow.com/a/20196591/521754 (и я вижу, что вы заслуживаете повышения :)). Спасибо за ваши усилия Люк! Я предоставлю конкретный способ того, как я справлялся с ситуацией для всех, кого это интересует. – despot