@RunWith (MockitoJUnitRunner.class) против MockitoAnnotations.initMocks (это)

118

При написании нового теста jUnit4 мне интересно, использовать ли @RunWith (MockitoJUnitRunner.class) или MockitoAnnotations.initMocks (это) .

Я создал новый тест, и мастер автоматически сгенерировал тест с помощью Runner. В документации Javadocs для MockitoJUnitRunner указано следующее:

Совместимый с JUnit 4.4 и выше, этот бегун добавляет следующее поведение:

Инициализирует макеты, аннотированные с помощью Mock, поэтому явное использование MockitoAnnotations.initMocks (Object) не требуется. Моки инициализируются перед каждым методом тестирования. проверяет использование фреймворка после каждого метода тестирования.

Мне неясно, имеет ли использование Runner какое-либо преимущество перед методом initMocks (), который я использовал в прошлом.

Приветствуются любые мысли или ссылки!

OceanBlue
источник

Ответы:

147

MockitoJUnitRunnerдает вам автоматическую проверку использования фреймворка, а также автоматический initMocks().

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

  • Вы вызываете статический whenметод, но не завершаете заглушку соответствием thenReturn, thenThrowили then. (Ошибка 1 в приведенном ниже коде)

  • Вы вызываете verifyимитацию, но забываете предоставить вызов метода, который пытаетесь проверить. (Ошибка 2 в приведенном ниже коде)

  • Вы вызываете whenметод после doReturn, doThrowили doAnswerи передать макет, но забудьте указать метод , который вы пытаетесь заглушкой. (Ошибка 3 в приведенном ниже коде)

Если у вас нет подтверждения использования фреймворка, об этих ошибках не сообщается до следующего вызова метода Mockito. Это может быть

  • в том же методе тестирования (например, ошибка 1 ниже),
  • в следующем методе тестирования (например, ошибка 2 ниже),
  • в следующем тестовом классе.

Если они возникают в последнем запущенном вами тесте (например, ошибка 3 ниже), о них вообще не будет сообщено.

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

@Test
public void test1() {

    // ERROR 1
    // This compiles and runs, but it's an invalid use of the framework because 
    // Mockito is still waiting to find out what it should do when myMethod is called.
    // But Mockito can't report it yet, because the call to thenReturn might 
    // be yet to happen.
    when(myMock.method1());

    doSomeTestingStuff();

    // ERROR 1 is reported on the following line, even though it's not the line with
    // the error.
    verify(myMock).method2();

}

@Test
public void test2() {

    doSomeTestingStuff();

    // ERROR 2
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call to verify.  But Mockito can't report 
    // it yet, because the call to the method that's being verified might 
    // be yet to happen.
    verify(myMock);
}

@Test
public void test3() {

    // ERROR 2 is reported on the following line, even though it's not even in 
    // the same test as the error.
    doReturn("Hello").when(myMock).method1();


    // ERROR 3
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call is being stubbed.  But Mockito can't 
    // report it yet, because the call to the method that's being stubbed might 
    // be yet to happen.

    doReturn("World").when(myMock);

    doSomeTestingStuff(); 

    //  ERROR 3 is never reported, because there are no more Mockito calls. 
}

Когда я впервые написал этот ответ более пяти лет назад, я написал

Поэтому я бы порекомендовал использовать MockitoJUnitRunnerвезде, где это возможно. Однако, как правильно указал Томаш Нуркевич, вы не можете использовать его, если вам нужен другой бегун JUnit, такой как Spring.

Моя рекомендация изменилась. Команда Mockito добавила новую функцию с тех пор, как я впервые написал этот ответ. Это правило JUnit, которое выполняет ту же функцию, что и MockitoJUnitRunner. Но так лучше, потому что это не исключает использования других бегунов.

Включают

@Rule 
public MockitoRule rule = MockitoJUnit.rule();

в вашем тестовом классе. Это инициализирует макеты и автоматизирует проверку фреймворка; просто нравится MockitoJUnitRunner. Но теперь вы можете использовать SpringJUnit4ClassRunnerили любой другой JUnitRunner. Начиная с Mockito 2.1.0, есть дополнительные параметры, которые точно определяют, о каких проблемах следует сообщать.

Дауд ибн Карим
источник
Я определенно не могу сказать, что они такие же. в одном тестовом случае установка junit runner для меня не работает и не вводит мои макеты должным образом, если я не выполняю настройку initMocks
dtc
Мы используем testng 6.8.8 + mockito 1.10.19 и, очевидно, мы не можем использовать MockitoJUnitRunner, но структура проверки по-прежнему работает! И он работает точно так же, как @David Wallace. Кто-нибудь может объяснить? Это потому, что у нас все еще есть обратные вызовы @ Before * и MockitoAnnotations.initMocks (this)?
yuranos
@ yuranos87 Похоже, вам следует задать новый вопрос. Не забудьте включить свой код, когда вы это сделаете - бессмысленно спрашивать «почему этот код делает XYZ», если вы не показываете код.
Давуд ибн Карим
1
использование решения TestRunner намного превосходит @Rule
Правило
1
@alexandroid Мое лучшее предложение - написать собственный ответ, используя @ExtendWith. На самом деле я не знаю об этом. Самое замечательное в Stack Overflow заключается в том, что на такой вопрос вы можете получить несколько правильных ответов.
Давуд ибн Карим
23

Использование runner позволяет вам немного сэкономить на коде (нет необходимости в @Beforeметоде). С другой стороны, использование раннера иногда невозможно, например, когда вы уже используете его SpringJUnit4ClassRunner.

Вот и все. Это просто вопрос предпочтения.

Томаш Нуркевич
источник
2
Помимо строки initMocks (), метод @Before все равно понадобится для любой другой настройки, верно?
OceanBlue
2
@OceanBlue: Конечно, если ваш @Beforeметод содержал что-либо, кроме initMocks()того, что вы должны сохранить его после перехода на runner.
Томаш Нуркевич
Ответ Дэвида Уоллеса о проверке фреймворка полностью отвечает на мой вопрос, поэтому я принял его, но +1 за то, что указал, что этот бегун не может использоваться с другим, например Spring. Спасибо!
OceanBlue
1
Я использую Spring Boot и могу сказать, что он SpringJUnit4ClassRunnerавтоматически инициализирует mock-объекты. Но я не знаю, что такое обычная весна.
gustavohenke