不要なスタブの例外を解決する方法


100

私のコードは以下の通りです、

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

解決方法を教えてください

回答:


120

交換してください@RunWith(MockitoJUnitRunner.class)@RunWith(MockitoJUnitRunner.Silent.class)


44
ようこそ。OPがそのようなコードを置き換える必要がある理由を説明するために、回答を更新する価値があります。これは彼らと将来の訪問者が理解するのに役立ちます。
バグ

5
ところで、サイレントでは@RunWith(MockitoJUnitRunner.Silent.class)ありません
fgysinがモニカを復活させます2017

6
コトリン:@RunWith(MockitoJUnitRunner.Silent::class)
ファンサラビア、

9
なぜこの回答が説明なしで賛成票を集め続けるのかわからない。他の回答はより意味があり正確です。
Yogesh

8
これは問題を解決しませんが、単にエラーメッセージを抑制し、クラス内の他のすべてのテスト(存在する場合)にも影響します。
フェンサー

98

最初に、テストロジックを確認する必要があります。通常は3つのケースがあります。まず、間違ったメソッドをあざけっています(タイプミスをしたか、誰かがテスト済みのコードを変更したため、あざけられたメソッドが使用されなくなりました)。次に、このメソッドが呼び出される前にテストが失敗します。3番目に、if / switch分岐がコードのどこかに分岐しているため、モックされたメソッドが呼び出されません。

これが最初のケースである場合は、コードで使用されているメソッドのモックメソッドを常に変更する必要があります。2番目と3番目では状況によって異なります。通常、このモックが不要な場合は削除してください。ただし、パラメーター化されたテストで特定のケースが発生することもあります。この場合、この別の方法を取るか、早期に失敗します。次に、このテストを2つ以上の個別のテストに分割できますが、それが常に良いとは限りません。おそらく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)は、私のセットアップで厳密さを調整する最も簡単な方法です。ありがとう!
マット

4
この回答は、可能性の良い概要を提供します。ただし、を使用してケースごとに寛容な厳格さを設定することもできMockito.lenient().when(...)ます。この特定の問題のために、それは次のようになりますMockito.lenient().when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);
ネクサス

テスト階層を扱う場合、ExtendWithをスーパークラスに定義し、MockitoSettingsをサブクラスに定義します。これが私の費用の誰かのために時間を節約することを望みます。
miracle_the_V

32

サイレントは解決策ではありません。テストでモックを修正する必要があります。こちらの公式ドキュメントをご覧ください

不要なスタブとは、テストの実行中に実現されなかったスタブメソッドの呼び出しです(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
 ...

テストの実行中に、スタブメソッドの1つがテスト中のコードで実現されなかったことに注意してください。浮遊スタブは、開発者の見落とし、コピーと貼り付けのアーティファクト、またはテスト/コードを理解できない影響である可能性があります。いずれにせよ、開発者は不要なテストコードを取得することになります。コードベースをクリーンで保守可能な状態に保つには、不要なコードを削除する必要があります。それ以外の場合、テストは読みにくく、理由付けが困難です。

未使用のスタブの検出の詳細については、MockitoHintを参照してください。


13
少数のテストのビジネスロジックのために、1つのスタブから返されたアイテムが使用されない、同様の@BeforeEachセットアップに対して8〜9個のテストを作成する多くの状況があります。(A)複数のテストに分割し、\ @ BeforeEachセクションから1つの項目を差し引いたものを効果的にコピー/貼り付けできます(B)Mockitoがエモについている1行をコピーして、それを使用する6つのテストに貼り付けますない2ではない(C)サイレントを使用する。サイレント/警告を使用することを好みます。壊れたテストではありません。
RockMeetHardplace

1
@RockMeetHardplace、Silentは解決策はありません。すぐにコピー/貼り付けが少なくなりますが、プロジェクトの新しいユーザーによるテストを維持する場合、これは問題になります。Mockito書店がそうするなら、それは無駄ではありません。
ステファン・グリオン

2
@sgrillon:しかし、このシステムは大量の誤検知を検出します。つまり、何かが未使用であると表示されますが、スタブを削除すると実行が中断されるため、それは明らかに使用されていません。テストコードを改善できないということではなく、重要なスタブ行を「不要」として検出してはならないということです。したがって、このチェックを無効にできることの重要性は、あまりにも熱心です。
カリガン

@Carighan、モックが正しくないと検出された場合、それはあなたが考えているものではない可能性があります。これにより、バグが存在する可能性がある間にOKテストが行​​われます。
ステファン・グリオン

@sgrillon、ごめんなさい。これには、テストの実行順序に応じて「誤ったヒット」を生成するバグがあり、1つのテストで使用されたが別のテストで上書きされたスタブによってトリガーされることが判明しました。私が知る限り、それは長い間修正されています。
カリガン

27

私にとって@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());

言うまでもなく、テストコードを確認する必要がありますが、最初にコンパイルしたものとテストを実行する必要がありました;)


6
私見では。これは、テストクラス全体を黙らせる代わりに、ここで見つけた最も有用な答えです。
priyeshdkr

私はモックを1つだけ抑制したかったので、これは私にとって最良の答えです。しかし、実際にはOPに対する答えではありません。
ハンスウーターズ

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

whenここで何かをするあなたのモックを設定します。ただし、この行以降は、このモックを使用しません(を実行することを除くverify)。Mockito whenは、ラインが無意味であることを警告します。おそらくあなたは論理エラーを犯しましたか?


あなたの助けをありがとう
VHS

whenとverifyの両方のステートメントが必要で、さらに先へ進む方法を親切に提案しています
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();
    }
}

必要に応じて、テストをスタブにリファクタリングすることを検討します。


2

代わりにこのスタイルを使用している場合:

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

に置き換えてください:

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

2

交換する

@RunWith(MockitoJUnitRunner.class)

@RunWith(MockitoJUnitRunner.Silent.class)

または削除@RunWith(MockitoJUnitRunner.class)

または、(不正なスタブとして表示される)不要なモッ​​クコールをコメントアウトする


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

それは今働いています。


0

大規模なプロジェクトの場合、これらの例外のそれぞれを修正することは困難です。同時に、使用Silentはお勧めしません。それらのリストを指定して、不要なスタブをすべて削除するスクリプトを作成しました。

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

mvn出力をコピーして貼り付け、正規表現を使用してこれらの例外のリストを記述し、スクリプトに残りの処理を任せるだけです。


0

モックするときにany()を使用する場合は、@ RunWith(MockitoJUnitRunner.class)を@RunWith(MockitoJUnitRunner.Silent.class)で改造する必要があります。


0

モックを作成し、そのモックが使用されていない場合、未使用のスタブ例外がスローされます。あなたの場合、そのモックは実際には呼び出されません。したがって、そのエラーをスローしています。したがって、どちら@RunWith(MockitoJUnitRunner.class)@RunWith(MockitoJUnitRunner.Silent.class)使用すればエラーは解消され ます。それでも使用したい@RunWith(MockitoJUnitRunner.class)場合は、モックした関数が実際に呼び出されているかどうかにかかわらず、ロジックをデバッグしてみてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.