26

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

シナリオ:

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()(これは動作します)?

4

6 に答える 6

13

mockito 2.x では、JDK 8 のデフォルトのメソッドがサポートされています。

mockito 1.x では不可能です


古い答え

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

JDK8 の状態

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

EDIT 1 :ディフェンダー メソッドデフォルト メソッドは、同じものの異なる名前です。

一部のオペコードは Java 8 で異なるセマンティクスを持っているなどの場合に、Java 8 オペコードを適切に処理するモックメーカーの代替品を期待しています。

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

于 2014-12-27T13:17:53.177 に答える
11

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);
于 2016-01-19T00:02:05.500 に答える
2

インターフェイスを実装することで、この制限を回避できます (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 { }
  }
}
于 2016-12-30T12:25:25.670 に答える
2

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

私が見つけた最も簡単な解決策は、テストクラス内にプライベート抽象クラスを使用してインターフェイスを実装し、そのクラスをモックすることです (@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());
    }
}
于 2017-05-05T12:35:04.663 に答える