26

我是 mockito 的忠实粉丝,不幸的是,对于我使用 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()除了实现接口和在接口上(这行得通)之外,你能不能让它以其他方式工作?

4

6 回答 6

13

mockito 2.x支持JDK 8 默认方法。

使用mockito 1.x不可能的


旧答案

不幸的是,它还不可能(mockito 1.10.19),来自README.mdgithub'page

JDK8 状态

如果您远离默认方法(又名防御者方法),Mockito 应该可以在 JDK8 上正常工作。Lambda 的使用可能与 Answers 一样好。目前我们不确定 JDK8 的每个特性,比如序列化使用 lambda 的模拟。不过,欢迎错误报告和拉取请求(贡献指南)。

编辑 1防御者方法默认方法是同一事物的不同名称。

我希望一个 mockmaker 替代品能够正确处理 Java 8 操作码,因为某些操作码在 Java 8 中具有不同的语义。

编辑 2:更新了 mockito 自述文件,并相应地引用了此引用

于 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 回答
4

Mockito(适用于版本 3)可以使用default方法。这是用 JUnit 5 重写的示例代码,因此它应该可以工作:

@ExtendWith(MockitoExtension.class)
class MockTest {
    @Mock(answer = Answers.CALLS_REAL_METHODS)
    private Foo foo;

    @Test
    void testDefaultMethodsWithMocks() {
        assertThat(foo.bar()).isEqualTo(42);
    }

    @FunctionalInterface
    private interface Foo {
        int foo();

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

调用真正的方法回答确实在最新的 Mockito 中工作。作为一般规则,扩展使模拟的创建更具声明性,但该mock方法还提供了支持默认答案的重载,如上面的@Mock注释所示:https ://javadoc.io/doc/org.mockito/mockito- core/latest/org/mockito/Mockito.html#mock-java.lang.Class-org.mockito.stubbing.Answer-

于 2020-11-20T14:23:12.753 回答
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(Spring, 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());
    }
}
于 2017-05-05T12:35:04.663 回答
1

另一种解决方案是使用Spy此处所述的 a:https ://stackoverflow.com/a/54915791/3636822

于 2020-10-28T13:57:55.060 回答