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";
    }
}

但它失败了。我尝试了一些“hack”并且它有效。

   @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 常见问题解答

Mockito 的局限性是什么

  • 不能模拟最终方法——它们的真实行为无一例外地被执行。Mockito 无法警告您模拟 final 方法,因此请保持警惕。
于 2010-09-25T15:48:40.723 回答
35

在 Mockito 中不支持模拟最终方法。

正如 Jon Skeet 评论的那样,您应该寻找一种方法来避免对 final 方法的依赖。也就是说,有一些方法可以通过字节码操作(例如使用 PowerMock)

Mockito 和 PowerMock 之间的比较将详细说明事情。

于 2010-09-25T12:48:15.700 回答
23

您可以将 Powermock 与 Mockito 一起使用,然后您不需要继承 B.class。只需将其添加到测试类的顶部

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

@PrepareForTest指示 Powermock 检测 B.class 以使 final 和 static 方法可模拟。这种方法的一个缺点是您必须使用 PowerMockRunner,这会阻止使用其他测试运行器,例如 Spring 测试运行器。

于 2012-09-20T12:01:37.663 回答
17

Mockito 2 现在支持模拟 final 方法,但这是一个“孵化”功能。它需要一些步骤来激活它,如下所述: https ://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-最终类方法

于 2016-10-09T13:39:32.560 回答
11

Mockito 2.x 现在支持 final 方法和 final 类存根。

从文档

最终类和方法的模拟是一个孵化、选择加入的特性。src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker必须通过创建包含单行的文件来显式激活此功能:

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)方法。然后测试只是在等待 alevel为 5 的呼叫。

一般来说,为行为扩展一个类并不是一个坏主意,如果不是太复杂的话,它可能比模拟更好。

于 2013-09-30T23:36:14.440 回答