web-dev-qa-db-ja.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)

解決方法を手伝ってください

60
VHS

@RunWith(MockitoJUnitRunner.class)@RunWith(MockitoJUnitRunner.Silent.class)に置き換えます。

87
Sumit

最初にテストロジックを確認してください。通常3つのケースがあります。まず、あなたは間違った方法を偽造しています(あなたはタイプミスをしたか、誰かが偽造された方法がもはや使用されないようにテストされたコードを変更しました)。次に、このメソッドが呼び出される前にテストが失敗しています。第三に、/ 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 {
}
45
Dcortez
 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

ここのwhenは、モックが何かをするように設定します。ただし、この行以降は、このモックを使用しないでください(verifyを除く)。 Mockitoはwhen行はそれゆえ無意味であるとあなたに警告します。おそらくあなたは論理エラーを犯しましたか?

19
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
 ...

テスト実行中に、スタブ化されたメソッドの1つがテスト中のコードで実現されたことがないことに注意してください。厄介なスタブは、開発者の見落とし、コピー&ペーストのアーティファクト、あるいはテスト/コードを理解していない効果かもしれません。どちらにしても、開発者は不必要なテストコードになります。コードベースをクリーンで維持可能な状態に保つために、不要なコードを削除する必要があります。さもなければテストは読みにくくなり、それについて推論します。

未使用のスタブを検出することについてもっと知るためにはMockitoHintを見てください。

10
sgrillon

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

言うまでもなく、テストコードを見るべきですが、まず最初に、コンパイルしたものとテストを実行する必要がありました。

7
philonous

スタックトレースの一部を見ると、他の場所で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

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

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

mvnの出力をコピー&ペーストして、regexを使用してこれらの例外のリストを書き、残りをスクリプトに処理させるだけです。

0
mohitmayank