简体   繁体   English

最终方法 mocking

[英]Final method mocking

I need mock some class with final method using mockito. I have wrote something like this我需要使用 mockito 的最终方法模拟一些 class。我写了这样的东西

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

But it fails.但它失败了。 I tried some "hack" and it works.我尝试了一些“破解”并且它有效。

   @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());
    }

It works, but "smells".它有效,但“闻起来”。

So, Where is the right way?那么,正确的方法在哪里呢?

Thanks.谢谢。

There is no support for mocking final methods in Mockito.在 Mockito 中不支持模拟最终方法。

As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method.正如 Jon Skeet 评论的那样,您应该寻找一种方法来避免对 final 方法的依赖。 That said, there are some ways out through bytecode manipulation (eg with PowerMock)也就是说,有一些方法可以通过字节码操作(例如使用 PowerMock)

A comparison between Mockito and PowerMock will explain things in detail. Mockito 和 PowerMock 之间比较将详细说明事情。

From the Mockito FAQ :Mockito 常见问题解答

What are the limitations of Mockito Mockito 的局限性是什么

  • Cannot mock final methods - their real behavior is executed without any exception.不能模拟最终方法——它们的真实行为无一例外地被执行。 Mockito cannot warn you about mocking final methods so be vigilant. Mockito 无法警告您模拟 final 方法,因此请保持警惕。

You can use Powermock together with Mockito, then you do not need to subclass B.class.您可以将 Powermock 与 Mockito 一起使用,然后您不需要继承 B.class。 Just add this to the top of your test class只需将其添加到测试类的顶部

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

@PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. @PrepareForTest指示 Powermock 检测 B.class 以使 final 和 static 方法可模拟。 A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.这种方法的一个缺点是您必须使用 PowerMockRunner,这会阻止使用其他测试运行器,例如 Spring 测试运行器。

Mockito 2 now supports mocking final methods but that's an "incubating" feature. Mockito 2 现在支持模拟 final 方法,但这是一个“孵化”功能。 It requires some steps to activate it which are described here: https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods它需要一些步骤来激活它,如下所述: https : //github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-最终类方法

Mockito 2.x now supports final method and final class stubbing. Mockito 2.x 现在支持 final 方法和 final 类存根。

From the docs : 从文档

Mocking of final classes and methods is an incubating, opt-in feature.最终类和方法的模拟是一个孵化、选择加入的特性。 This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:必须通过创建包含一行的文件src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker来显式激活此功能:

mock-maker-inline

After you create this file you can do:创建此文件后,您可以执行以下操作:

 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());

In subsequent milestones, the team will bring a programmatic way of using this feature.在随后的里程碑中,团队将带来使用此功能的程序化方式。 We will identify and provide support for all unmockable scenarios.我们将为所有不可模拟的场景识别并提供支持。

Assuming that B class is as below:假设B类如下:

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

There is a better way to do this without using PowerMockito framework.有一种更好的方法可以在不使用 PowerMockito 框架的情况下做到这一点。 You can create a SPY for your class and can mock your final method.你可以为你的类创建一个 SPY 并且可以模拟你的 final 方法。 Below is the way to do it:以下是执行此操作的方法:

@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());

}

Mockito can be used to mock final classes or final methods. Mockito 可用于模拟最终类或最终方法。 The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.问题是,这不是来自 Mockito 的开箱即用功能,需要明确配置。

So, in order to do that,所以,为了做到这一点,

Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below在项目的src/test/resources/mockito-extensions目录下创建一个名为org.mockito.plugins.MockMaker的文本文件,并添加如下一行文本

mock-maker-inline

Once done, you can use the mockito's when method to mock the behaviour like any other regular method.完成后,您可以使用 mockito 的when方法像任何其他常规方法一样模拟行为。

See detailed examples here在此处查看详细示例

I just did this same thing.我只是做了同样的事情。 My case was that I wanted to ensure the method didn't "Cause" an error but since it's a catch/log/return method I couldn't test for it directly without modifying the class.我的情况是我想确保该方法不会“导致”错误,但由于它是一个 catch/log/return 方法,我无法在不修改类的情况下直接测试它。

I wanted to simply mock the logger I passed in, but something about mocking the "Log" interface didn't seem to work and Mocking a class like "SimpleLog" didn't work because those methods are final.我想简单地模拟我传入的记录器,但是关于模拟“Log”接口的一些东西似乎不起作用,并且模拟像“SimpleLog”这样的类也不起作用,因为这些方法是最终的。

I ended up creating an anonymous inner class extending SimpleLog that overrid the base-level "log(level, string, error)" method that the others all delegate to, then just waiting for a call with a "level" of 5.我最终创建了一个扩展 SimpleLog 的匿名内部类,它覆盖了其他人都委托给的基本级别的“log(level, string, error)”方法,然后只等待“级别”为 5 的调用。

In general, extending a class for behavior isn't really a bad idea, might be preferable to mocking anyway if it's not too complicated.一般来说,为行为扩展一个类并不是一个坏主意,如果不是太复杂的话,它可能比模拟更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM