[java] 불필요한 스터 빙 예외를 해결하는 방법

내 코드는 다음과 같습니다.

@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)

해결 방법을 도와주세요



답변

교체 @RunWith(MockitoJUnitRunner.class)와 함께 @RunWith(MockitoJUnitRunner.Silent.class).


답변

처음에는 테스트 로직을 확인해야합니다. 일반적으로 3 가지 경우가 있습니다. 첫째, 잘못된 방법을 조롱하고 있습니다 (오타를 만들었거나 누군가가 테스트 된 코드를 변경하여 모의 방법이 더 이상 사용되지 않도록합니다). 둘째,이 메서드가 호출되기 전에 테스트가 실패합니다. 셋째, 논리가 코드의 어딘가에 잘못된 if / switch 분기에 속하므로 모의 메서드가 호출되지 않습니다.

이것이 첫 번째 경우라면 항상 코드에서 사용되는 모의 메서드를 변경하고 싶습니다. 두 번째와 세 번째는 다릅니다. 일반적으로 사용하지 않는 경우이 mock을 삭제해야합니다. 그러나 때때로 매개 변수화 된 테스트에는이 다른 경로를 사용하거나 더 일찍 실패해야하는 특정 사례가 있습니다. 그런 다음이 테스트를 두 개 이상의 개별 테스트로 나눌 수 있지만 항상 좋은 것은 아닙니다. 3 개의 인수 공급자가있는 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 {
}


답변

침묵은 해결책이 아닙니다. 테스트에서 모의를 수정해야합니다. 여기에서 공식 문서를 참조 하십시오 .

불필요한 스텁은 테스트 실행 중에 실현되지 않은 스텁 메서드 호출입니다 (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를 참조하십시오.


답변

나에게는 제안도 효과 가 @Rule없었습니다 @RunWith(MockitoJUnitRunner.Silent.class). mockito-core 2.23.0으로 업그레이드 한 레거시 프로젝트였습니다.

다음 UnnecessaryStubbingException을 사용하여 제거 할 수 있습니다 .

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

대신에:

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

말할 필요도없이 테스트 코드를 봐야하지만, 우리는 무엇보다도 먼저 컴파일하고 테스트를 실행해야했습니다.)


답변

 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

when여기에 뭔가를 당신의 모의를 구성합니다. 그러나이 줄 뒤에는 더 이상이 모의를 사용하지 않습니다 (를 수행하는 것 제외 verify). Mockito는 when따라서 선이 무의미하다고 경고합니다 . 논리 오류를 범 하셨나요?


답변

스택 추적의 일부를 보면 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();
    }
}

필요한 경우 스텁으로 테스트를 리팩토링하는 것을 고려하고 싶습니다.


답변

대신이 스타일을 사용하는 경우 :

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

다음으로 교체하십시오.

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