73

mockitoを使用してfinalメソッドでクラスをモックする必要があります。私はこのようなものを書きました

@Test
public void test() {
    B b = mock(B.class);
    doReturn("bar called").when(b).bar();   
    assertEquals("must be \"overrided\"", "bar called", b.bar());
    //bla-bla
}


class B {
    public final String bar() {
        return "fail";
    }
}

しかし、それは失敗します。私はいくつかの「ハック」を試しましたが、うまくいきました。

   @Test
   public void hackTest() {
        class NewB extends B {
            public String barForTest() {
                return bar();
            }
        }
        NewB b = mock(NewB.class);
        doReturn("bar called").when(b).barForTest();
        assertEquals("must be \"overrided\"", "bar called", b.barForTest());
    }

動作しますが、「においがします」。

それで、正しい方法はどこにありますか?

ありがとう。

4

7 に答える 7

37

Mockito FAQから:

Mockitoの制限は何ですか

  • 最終的なメソッドをモックすることはできません-それらの実際の動作は例外なく実行されます。Mockitoは、最終的なメソッドをモックすることについて警告することはできないので、注意してください。
于 2010-09-25T15:48:40.723 に答える
35

Mockitoではfinalメソッドをモックすることはサポートされていません。

Jon Skeetがコメントしたように、finalメソッドへの依存を回避する方法を探す必要があります。とは言うものの、バイトコード操作(例:PowerMock)を介していくつかの方法があります

MockitoとPowerMockを比較すると、詳細が説明されます。

于 2010-09-25T12:48:15.700 に答える
23

PowermockをMockitoと一緒に使用できる場合は、B.classをサブクラス化する必要はありません。これをテストクラスの一番上に追加するだけです

@RunWith(PowerMockRunner.class)
@PrepareForTest(B.class)

@PrepareForTestPowermockにB.classをインストルメントして、finalメソッドとstaticメソッドをモック可能にするように指示します。このアプローチの欠点は、Springテストランナーなどの他のテストランナーを使用できないようにするPowerMockRunnerを使用する必要があることです。

于 2012-09-20T12:01:37.663 に答える
17

Mockito 2は、最終メソッドのモックをサポートするようになりましたが、これは「インキュベーション」機能です。ここで説明されているように、アクティブ化するためのいくつかの手順が必要です: https ://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of- final-classesmethods

于 2016-10-09T13:39:32.560 に答える
11

Mockito 2.xは、finalメソッドとfinalクラスのスタブをサポートするようになりました。

ドキュメントから

最終的なクラスとメソッドのモックは、インキュベーションのオプトイン機能です。src/test/resources/mockito-extensions/org.mockito.plugins.MockMakerこの機能は、次の1行を含むファイルを作成して明示的にアクティブ化する必要があります。

mock-maker-inline

このファイルを作成した後、次のことができます。

final class FinalClass {
  final String finalMethod() { return "something"; }
}

FinalClass concrete = new FinalClass(); 

FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");

assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());

その後のマイルストーンでは、チームはこの機能をプログラムで使用する方法を提供します。モックできないすべてのシナリオを特定し、サポートを提供します。

于 2018-12-18T16:37:58.593 に答える
3

Bクラスが以下のようになっていると仮定します。

class B {
    private String barValue;
    public final String bar() {
        return barValue;
    }
    public void final setBar(String barValue) {
        this.barValue = barValue;
    }
}

PowerMockitoフレームワークを使用せずにこれを行うためのより良い方法があります。クラスのSPYを作成し、finalメソッドをモックすることができます。以下はそれを行う方法です:

@Test
public void test() {

    B b  = new B();
    b.setBar("bar called") //This should the expected output:final_method_bar()
    B spyB = Mockito.spy(b);
    assertEquals("bar called", spyB.bar());

}
于 2017-04-25T14:02:11.953 に答える
0

私はこれと同じことをしました。私の場合は、メソッドがエラーを引き起こさないようにしたかったのです。ただし、catch / log / returnメソッドであるため、クラスを変更せずに直接テストすることはできませんでした。

渡したロガーを単純にモックしたかったのですが、Logインターフェースのモックはうまくいかなかったようで、クラスのモックはSimpleLogこれらのメソッドが最終的なものであるため機能しませんでした。

最終的に、他のすべてが委任するSimpleLog基本レベルのメソッドを上書きする匿名の内部クラスを作成しました。log(level, string, error)次に、テストは5の呼び出しを待機していますlevel

一般に、動作のためにクラスを拡張することは実際には悪い考えではなく、それほど複雑でなければ、とにかくモックするよりも好ましいかもしれません。

于 2013-09-30T23:36:14.440 に答える