it-roy-ru.com

Как разрешить исключение из-за ненужной заглушки

Мой код, как показано ниже, 

@RunWith(MockitoJUnitRunner.class)
public class MyClass {

    private static final String code ="Test";

    @Mock
     private MyClassDAO dao;

    @InjectMocks
     private MyClassService Service = new MyClassServiceImpl();

    @Test
     public void testDoSearch() throws Exception {
         final String METHOD_NAME = logger.getName().concat(".testDoSearchEcRcfInspections()");
         CriteriaDTO dto = new CriteriaDTO();
         dto.setCode(code);
         inspectionService.searchEcRcfInspections(dto);
         List<SearchCriteriaDTO> summaryList = new ArrayList<SearchCriteriaDTO>();
         inspectionsSummaryList.add(dto);
         when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
         verify(dao).doSearchInspections(dto);

      }
}

Я получаю ниже исключения

org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected in test class: Test
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at service.Test.testDoSearch(Test.Java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
  at org.mockito.internal.exceptions.Reporter.formatUnncessaryStubbingException(Reporter.Java:838)
  at org.mockito.internal.junit.UnnecessaryStubbingsReporter.validateUnusedStubs(UnnecessaryStubbingsReporter.Java:34)
  at org.mockito.internal.runners.StrictRunner.run(StrictRunner.Java:49)
  at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.Java:103)
  at org.Eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.Java:86)
  at org.Eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.Java:38)
  at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.Java:459)
  at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.Java:675)
  at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.Java:382)
  at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.Java:192)

Пожалуйста, помогите мне, как решить

46
VHS

Замените @RunWith(MockitoJUnitRunner.class) на @RunWith(MockitoJUnitRunner.Silent.class).

81
Sumit

Сначала вы должны проверить свою тестовую логику. Обычно бывает 3 случая. Во-первых, вы издеваетесь над неправильным методом (вы сделали опечатку или кто-то изменил проверенный код, чтобы смоделированный метод больше не использовался). Во-вторых, ваш тест не пройден до вызова этого метода. В-третьих, ваша логика ошибается, если где-то в коде ветвь/switch, так что смоделированный метод не вызывается.

Если это первый случай, вы всегда хотите сменить метод, который используется в коде. Со вторым и третьим это зависит. Обычно вы должны просто удалить этот макет, если он бесполезен. Но иногда в параметризованных тестах есть определенные случаи, которые должны идти по другому пути или провалиться раньше. Затем вы можете разделить этот тест на два или более отдельных, но это не всегда хорошо выглядит. 3 метода тестирования с возможно тремя поставщиками аргументов могут сделать ваш тест нечитаемым. В этом случае для JUnit 4 вы исключаете это исключение либо 

@RunWith(MockitoJUnitRunner.Silent.class) 

аннотации или если вы используете подход правила

@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);

или (такое же поведение)

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

Для тестов JUnit 5 вы можете отключить это исключение, используя аннотацию, предоставленную в пакете mockito-junit-jupiter.

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
26
Dcortez
 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

Здесь when настраивает ваш макет, чтобы что-то делать. Тем не менее, вы больше не будете использовать этот макет после этой строки (кроме verify). Mockito предупреждает вас, что строка when бессмысленна. Возможно, вы сделали логическую ошибку?

16
john16384

Silent не является решением. Вы должны исправить свой макет в вашем тесте. Смотрите официальную документацию здесь.

Ненужные заглушки - это вызовы методов-заглушек, которые никогда не были реализованы во время выполнения теста (см. Также MockitoHint), пример:

//code under test:
 ...
 String result = translator.translate("one")
 ...

 //test:
 ...
 when(translator.translate("one")).thenReturn("jeden"); // <- stubbing realized during code execution
 when(translator.translate("two")).thenReturn("dwa"); // <- stubbing never realized
 ...

Обратите внимание, что один из заглушенных методов никогда не был реализован в тестируемом коде во время выполнения теста. Заблуждение может быть недосмотром разработчика, артефактом копирования-вставки или эффектом, не понимающим тест/код. В любом случае, разработчик получит ненужный тестовый код. Для того, чтобы поддерживать кодовую базу чистой и поддерживаемой, необходимо удалить ненужный код. В противном случае тесты сложнее читать и рассуждать о них.

Чтобы узнать больше об обнаружении неиспользованных заглушек, см. MockitoHint.

3
sgrillon

Глядя на часть вашей трассировки стека, кажется, что вы заглушаете dao.doSearch() в другом месте. Больше похоже на многократное создание заглушек одного и того же метода.

Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at service.Test.testDoSearch(Test.Java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.

Рассмотрим приведенный ниже тестовый класс, например:

@RunWith(MockitoJUnitRunner.class)
public class SomeTest {
    @Mock
    Service1 svc1Mock1;

    @Mock
    Service2 svc2Mock2;

    @InjectMock
    TestClass class;

    //Assume you have many dependencies and you want to set up all the stubs 
    //in one place assuming that all your tests need these stubs.

    //I know that any initialization code for the test can/should be in a 
    //@Before method. Lets assume there is another method just to create 
    //your stubs.

    public void setUpRequiredStubs() {
        when(svc1Mock1.someMethod(any(), any())).thenReturn(something));
        when(svc2Mock2.someOtherMethod(any())).thenReturn(somethingElse);
    }

    @Test
    public void methodUnderTest_StateUnderTest_ExpectedBehavior() {
        // You forget that you defined the stub for svcMock1.someMethod or 
        //thought you could redefine it. Well you cannot. That's going to be 
        //a problem and would throw your UnnecessaryStubbingException.
       when(svc1Mock1.someMethod(any(),any())).thenReturn(anyThing);//ERROR!
       setUpRequiredStubs();
    }
}

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

3
railomaya

Если вы используете этот стиль вместо:

@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

замените его на:

@Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
2
Greg

Для меня ни @Rule, ни @RunWith(MockitoJUnitRunner.Silent.class) предложения не сработали. Это был унаследованный проект, в котором мы обновились до версии 2.23.0. 

Мы могли бы избавиться от UnnecessaryStubbingException, используя: 

Mockito.lenient().when(mockedService.getUserById(any())).thenReturn(new User());

вместо: 

when(mockedService.getUserById(any())).thenReturn(new User());

Само собой разумеется, что вы должны смотреть на тестовый код, но нам нужно было скомпилировать материал и запустить тесты в первую очередь;) 

0
philonous