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


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.