web-dev-qa-db-ja.com

mockito(1.10.17)をインターフェイスのデフォルトメソッドで動作させることはできますか?

私はmockitoの大ファンですが、残念ながら 私のプロジェクトの1つ はJava 8を使用しますが、失敗します...

シナリオ:

_public final class MockTest
{
    @Test
    public void testDefaultMethodsWithMocks()
    {
        final Foo foo = mock(Foo.class);

        //when(foo.bar()).thenCallRealMethod();

        assertThat(foo.bar()).isEqualTo(42);
    }

    @FunctionalInterface
    private interface Foo
    {
        int foo();

        default int bar()
        {
            return 42;
        }
    }
}
_

残念ながら、テストは失敗し、foo.bar()は0を返します。

when()行のコメントを解除すると、スタックトレースが取得されます...

_Java.lang.NoSuchMethodError: Java.lang.Object.bar()I
    at com.github.fge.lambdas.MockTest.testDefaultMethodsWithMocks(MockTest.Java:18)
_

これは、Mavenで利用可能な最新の安定バージョンです。 Java 8 .. ..のこの新機能に関して、グーグルで調べても、mockitoのステータスについてはあまりわかりませんでした。

インターフェイスとspy()を実装する以外の方法で機能させることはできますか(これは機能します)?

22
fge

mockito 2.xの場合、JDK 8のデフォルトメソッドはsupportedです。

mockito 1.xの場合不可能


古い答え

残念ながら、github 'ページのREADME.mdからは、まだ可能ではありません(mockito 1.10.19)。

JDK8ステータス

MockitoはJDK8で正常に動作するはずですデフォルトのメソッド(別名ディフェンダーメソッド)から離れている場合。ラムダの使用法は、Answersでも同様に機能する可能性があります。ラムダを使用するモックのシリアル化など、現時点ではすべてのJDK8機能については不明です。ただし、エラーレポートとプルリクエストは大歓迎です(寄稿ガイド)。

編集1ディフェンダーメソッドおよびデフォルトメソッドは同じものの異なる名前です。

一部のオペコードのセマンティクスがJava 8)で異なる場合に、Java 8オペコードを適切に処理するモックメーカーの置き換えを期待しています。

編集2:mockito readmeを更新し、それに応じてこの引用を更新しました

11
Brice

Mockito 2.0.38-betaを試しましたが、そのバージョンではすでに機能しています。ただし、Mockitoには、デフォルトの実装を呼び出すように明示的に指示する必要があります。

Foo foo = mock(Foo.class);
assertThat(foo.bar()).isEqualTo(0);

when(foo.bar()).thenCallRealMethod();
assertThat(foo.bar()).isEqualTo(42);
5
Jan X Marek

この制限を回避するには、インターフェイス(Mockito 1.10.19でテスト済み)を実装します。

public class TestClass {
  @Mock ImplementsIntWithDefaultMethods someObject;


  @Test public void test() throws Exception {
    // calling default method on mocked subtype works
    someObject.callDefaultMethod();
  }


  /* Type that implements the interface */
  static class ImplementsIntWithDefaultMethods implements IntWithDefaultMethod { }

  /* Interface you need mocked */
  interface IntWithDefaultMethod {
    default void callDefaultMethod { }
  }
}
2
Mihai Bojin

Mockito(org.mockito:mockito-core:1.10.19)で同じ問題が発生しました。問題は次のとおりです。使用しているorg.springframework.boot:spring-boot-starter-test:1.4.3.RELEASEに依存しているため、Mockitoのバージョンを変更できません(2.7.22が機能します)(- 春、Mockitoの問題 )。

私が見つけた最も簡単な解決策は、テストクラス内にプライベート抽象クラスを使用してインターフェイスを実装し、それをモックすることです(@Mihai Bojinのソリューションとも比較してください)。このようにすることで、インターフェースに必要なすべてのメソッドを「実装」する手間を省くことができます。

MWE:

public interface InterfaceWithDefaults implements SomeOtherInterface {
    default int someConstantWithoutSense() {
        return 11;
    }
}

public class SomeTest {
    private abstract class Dummy implements InterfaceWithDefaults {}

    @Test
    public void testConstant() {
        InterfaceWithDefaults iwd = Mockito.mock(Dummy.class);

        Assert.assertEquals(11, iwd.someConstantWithoutSense());
    }
}
1
keocra