Java 最终方法模拟

Java 最终方法模拟,java,unit-testing,testing,mocking,mockito,Java,Unit Testing,Testing,Mocking,Mockito,我需要用mockito的最终方法模拟一些类。我写过这样的东西 @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(

我需要用mockito的最终方法模拟一些类。我写过这样的东西

@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";
    }
}
但它失败了。 我尝试了一些“黑客”,它的工作

   @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());
    }
它能工作,但“有味道”

那么,正确的道路在哪里


谢谢。

Mockito中不支持模拟final方法

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


A将详细解释事情。

在Mockito中不支持模拟final方法

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

A将详细解释事情。

来自:

Mockito的局限性是什么

  • 无法模拟最终方法-它们的真实行为是毫无例外地执行的。Mockito无法警告您有关模拟最终方法的信息,因此请保持警惕
从:

Mockito的局限性是什么

  • 无法模拟最终方法-它们的真实行为是毫无例外地执行的。Mockito无法警告您有关模拟最终方法的信息,因此请保持警惕

您可以将Powermock与Mockito一起使用,这样就不需要子类B.class。只需将其添加到测试类的顶部

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

@PrepareForTest
指示Powermock对B.class进行指令,使final和static方法可模拟。这种方法的一个缺点是,您必须使用PowerMockRunner,这就排除了使用其他测试运行程序(如Spring测试运行程序)的可能性。

您可以将Powermock与Mockito一起使用,那么您就不需要子类B.class。只需将其添加到测试类的顶部

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

@PrepareForTest
指示Powermock对B.class进行指令,使final和static方法可模拟。这种方法的一个缺点是必须使用PowerMockRunner,这就排除了使用其他测试运行程序,例如Spring测试运行程序。

我刚才也做了同样的事情。我的情况是,我希望确保该方法不会“导致”错误,但由于它是catch/log/return方法,因此在不修改类的情况下,我无法直接测试它

我想简单地模拟我传入的记录器,但是关于模拟“Log”接口的东西似乎不起作用,而模拟“SimpleLog”之类的类也不起作用,因为这些方法是最终的

我最终创建了一个扩展SimpleLog的匿名内部类,该类重写了其他人都委托给的基级“log(level,string,error)”方法,然后等待一个“level”为5的调用


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

我也做了同样的事情。我的情况是,我希望确保该方法不会“导致”错误,但由于它是catch/log/return方法,因此在不修改类的情况下,我无法直接测试它

我想简单地模拟我传入的记录器,但是关于模拟“Log”接口的东西似乎不起作用,而模拟“SimpleLog”之类的类也不起作用,因为这些方法是最终的

我最终创建了一个扩展SimpleLog的匿名内部类,该类重写了其他人都委托给的基级“log(level,string,error)”方法,然后等待一个“level”为5的调用


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

Mockito 2现在支持模拟最终方法,但这是一个“孵化”功能。激活它需要一些步骤,如下所述:

Mockito 2现在支持模拟最终方法,但这是一个“孵化”功能。激活它需要一些步骤,如下所述:

假设B类如下:

class B {
    private String barValue;
    public final String bar() {
        return barValue;
    }
    public void final setBar(String barValue) {
        this.barValue = barValue;
    }
}
有一种更好的方法可以做到这一点,而不用使用PowerMockito框架。 您可以为您的类创建一个间谍,并可以模拟您的最终方法。 以下是操作方法:

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

}

假设B类如下所示:

class B {
    private String barValue;
    public final String bar() {
        return barValue;
    }
    public void final setBar(String barValue) {
        this.barValue = barValue;
    }
}
有一种更好的方法可以做到这一点,而不用使用PowerMockito框架。 您可以为您的类创建一个间谍,并可以模拟您的最终方法。 以下是操作方法:

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

}

Mockito2.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());
在随后的里程碑中,团队将提供使用此功能的编程方式。我们将确定并支持所有不可修改的场景


Mockito2.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());
在随后的里程碑中,团队将提供使用此功能的编程方式。我们将确定并支持所有不可修改的场景


当然,理想情况是不需要模仿最终的方法。你还没有告诉我们你为什么要这么做。我通常努力保持我对接口的依赖性。。。你有没有办法使用一个接口来代理真实的类(假设你不能更改类本身)?这个类来自一些遗留代码。你没有修改它的选项吗?或代理