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


104

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

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

해결 방법을 도와주세요

답변:


118

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


44
어서 오십시오. OP가 이러한 코드를 대체해야하는 이유 를 설명하기 위해 답변을 업데이트하는 것이 좋습니다. 이것은 그들과 미래의 방문자가 이해하는 데 도움이 될 것입니다.
Bugs

5
BTW, 그것은이다 @RunWith(MockitoJUnitRunner.Silent.class)하지 SILENT
fgysin의 분석 재개 모니카

6
Kotlin :@RunWith(MockitoJUnitRunner.Silent::class)
Juan Saravia

11
이 답변이 설명없이 계속 찬성하는 이유를 모르겠습니다. 다른 답변은 더 의미 있고 정확합니다.
Yogesh

10
이것은 문제를 해결하지 못하지만 단순히 오류 메시지를 억제하고 클래스의 다른 모든 테스트 (있는 경우)에도 영향을줍니다.
Fencer

104

처음에는 테스트 로직을 확인해야합니다. 일반적으로 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 {
}

3
@MockitoSettings (strictness = Strictness.LENIENT)는 설정에서 엄격함을 조정하는 가장 간단한 방법입니다. 감사!
Matt

7
이 답변은 가능성에 대한 좋은 개요를 제공합니다. 그러나 Mockito.lenient().when(...);를 사용하여 케이스별로 관대 한 엄격 성을 설정할 수도 있습니다 . 이 것이 특정 질문에 대한Mockito.lenient().when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);
넥서스

테스트 계층을 다룰 때 수퍼 클래스에서 ExtendWith를 정의하고 서브 클래스에서 MockitoSettings를 정의합니다. 이것이 내 비용으로 누군가의 시간을 절약하기를 바랍니다.
miracle_the_V

37

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

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


14
하나의 스텁에서 반환 된 항목이 소수의 테스트에서 비즈니스 논리로 인해 사용되지 않는 유사한 @BeforeEach 설정에 대해 8-9 개의 테스트를 작성하는 많은 상황이 있습니다. (A) 여러 테스트로 나누고 \ @BeforeEach 섹션에서 하나의 항목을 빼고 효과적으로 복사 / 붙여 넣기를 할 수 있습니다. 그렇지 않은 2 또는 (C) 침묵을 사용하십시오. 나는 무음 / 경고를 선호한다. 깨진 테스트가 아닙니다.
RockMeetHardplace

1
@RockMeetHardplace, Silent는 해결책이 아니며 빠르게 복사 / 붙여 넣기를 덜 볼 수 있지만 프로젝트에서 새로운 사람이 테스트를 유지하면 문제가됩니다. Mockito 서점이 그렇게한다면 그것은 아무것도 아닙니다.
Stéphane GRILLON

2
@sgrillon :하지만이 시스템은 많은 오 탐지를 감지합니다. 즉, 무언가가 사용되지 않았다고 말하지만 스텁을 제거하면 실행이 중단되므로 분명히 그렇지 않습니다. 테스트 코드를 개선 할 수 없다는 것이 아니라 중요한 스터 빙 라인이 "불필요한"것으로 감지 되어서는 안됩니다 . 따라서이 검사를 비활성화 할 수있는 것이 중요하기 때문에 너무 열망합니다.
Carighan

1
@Carighan, 모의가 잘못된 것으로 감지되면 생각과 다를 수 있습니다. 이것은 버그가있을 수있는 동안 당신에게 OK 테스트를 제공합니다.
Stéphane GRILLON

@sgrillon, 죄송합니다. 테스트 실행 순서에 따라 하나의 테스트에서 사용되었지만 다른 테스트에서 덮어 쓴 스텁이 트리거하는 "거짓 적중"을 생성하는 버그가 있었던 것으로 나타났습니다. 내가 말할 수있는 한 오래 고정되어 있습니다.
Carighan

32

나에게는 제안도 효과 가 @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());

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


8
IMHO. 이것은 전체 테스트 클래스를 침묵시키는 대신에 내가 찾은 가장 유용한 대답입니다.
priyeshdkr

1
조롱을 한 번만 억제하고 싶었 기 때문에 이것이 가장 좋은 대답입니다. 그래도 OP에 대한 대답은 아닙니다.
Hans Wouters

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

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


도와 주셔서 감사합니다
VHS

나는 필요 모두 친절하게 더 이동하는 방법을 제안 할 때 문을 확인
VHS

2
테스트 클래스 ( Service) 에서 함수를 호출 하여 올바르게 반응하는지 확인합니다. 당신은 전혀 그렇게하지 않았습니다. 그래서 여기서 무엇을 테스트하고 있습니까?
john16384

3

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

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


1

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

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

다음으로 교체하십시오.

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

1

나는 Spy 개체에 메서드 UnnecessaryStubbingException를 사용하려고 할 때 가졌습니다 when. Mockito.lenient()예외를 음소거했지만 테스트 결과가 올바르지 않습니다.

Spy 개체의 경우 메서드를 직접 호출해야합니다.

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
class ArithmTest {

    @Spy
    private Arithm arithm;

    @Test
    void testAddition() {

        int res = arithm.add(2, 5);

        // doReturn(7).when(arithm).add(2, 5);
        assertEquals(res, 7);
    }
}

1

글쎄, 제 경우에는 Mockito 오류가 when또는 whenever스텁 뒤에 실제 메서드를 호출하도록 지시했습니다 . 우리가 방금 조롱 한 조건을 호출하지 않았기 때문에 Mockito는이를 불필요한 스텁 또는 코드로보고했습니다.

오류가 발생했을 때의 모습은 다음과 같습니다.

@Test
fun `should return error when item list is empty for getStockAvailability`() {
    doAnswer(
        Answer<Void> { invocation ->
            val callback =
                invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
            callback.onApiCallError(stockResultViewStateError)
            null
        }
    ).whenever(stockViewModelTest)
        .getStockAvailability(listOf(), getStocksApiCallBack)
}

그런 다음 메서드를 조롱하기 위해 when 문에서 언급 한 실제 메서드를 호출했습니다.

변경 사항은 다음과 같습니다. stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)

@Test
fun `should return error when item list is empty for getStockAvailability`() {
    doAnswer(
        Answer<Void> { invocation ->
            val callback =
                invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
            callback.onApiCallError(stockResultViewStateError)
            null
        }
    ).whenever(stockViewModelTest)
        .getStockAvailability(listOf(), getStocksApiCallBack)
    //called the actual method here
    stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
}

지금 작동하고 있습니다.


1

바꾸다

@RunWith(MockitoJUnitRunner.class)

@RunWith(MockitoJUnitRunner.Silent.class)

또는 제거@RunWith(MockitoJUnitRunner.class)

또는 원치 않는 모의 호출 (무단 스터 빙으로 표시됨)을 주석 처리합니다.


0

대규모 프로젝트의 경우 이러한 각 예외를 수정하기가 어렵습니다. 동시에 사용 Silent하지 않는 것이 좋습니다. 나는 그들 목록이 주어지면 불필요한 모든 스터 빙을 제거하는 스크립트를 작성했습니다.

https://gist.github.com/cueo/da1ca49e92679ac49f808c7ef594e75b

mvn출력 을 복사하여 붙여넣고 정규식을 사용하여 이러한 예외 목록을 작성하고 스크립트가 나머지를 처리하도록하면됩니다.


-1

조롱 할 때 any ()를 사용하는 경우 @RunWith (MockitoJUnitRunner.Silent.class)와 @RunWith (MockitoJUnitRunner.class)를 relpace해야합니다.


이것은 단순히 거짓입니다. any()올바르게 사용하면 일반 러너와 완벽하게 작동합니다.
Matthew Read

-1

mock을 만들고 해당 mock이 사용되지 않으면 사용되지 않는 스터 빙 예외가 발생합니다. 귀하의 경우에는 mock이 실제로 호출되지 않습니다. 따라서 그 오류가 발생합니다. 따라서, relpace @RunWith(MockitoJUnitRunner.class)@RunWith(MockitoJUnitRunner.Silent.class)오류를 제거하는 것입니다. 여전히 사용하고 싶다면 @RunWith(MockitoJUnitRunner.class)조롱 한 함수가 실제로 호출되는지 여부에 따라 논리 디버깅을 시도하십시오.


이것은 기존 답변에서 다루지 않은 내용을 추가하지 않습니다.
Matthew Read
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.