最终方法嘲笑

时间:2010-09-25 12:27:58

标签: java unit-testing testing mocking mockito

我需要使用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";
    }
}

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

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

它有效,但“闻起来”。

那么,正确的方式在哪里?

感谢。

7 个答案:

答案 0 :(得分:32)

来自Mockito FAQ

  

Mockito有哪些限制

     
      
  • 无法模拟最终方法 - 它们的实际行为在没有任何异常的情况下执行。 Mockito不能警告你嘲笑最终方法,所以请保持警惕。
  •   

答案 1 :(得分:29)

Mockito中没有支持嘲笑最终方法。

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

comparison between Mockito and PowerMock会详细解释事情。

答案 2 :(得分:19)

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

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

@PrepareForTest指示Powermock检测B.class以使最终和静态方法可模拟。这种方法的一个缺点是你必须使用PowerMockRunner,它不能使用其他测试运行器,例如Spring测试运行器。

答案 3 :(得分:14)

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

答案 4 :(得分:4)

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

From the docs

  

模拟最终课程和方法是一项令人振奋的选择功能。必须通过创建包含一行的文件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());
     

在随后的里程碑中,团队将带来使用该功能的编程方式。我们将为所有无法模拟的场景确定并提供支持。

答案 5 :(得分:3)

假设B类如下:

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

有一种更好的方法可以在不使用PowerMockito框架的情况下执行此操作。 您可以为您的班级创建一个SPY,并可以模拟您的最终方法。 以下是这样做的方法:

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

}

答案 6 :(得分:0)

我刚做了同样的事情。我的情况是我想确保方法没有“导致”错误,但因为它是一个catch / log / return方法,所以我无法在不修改类的情况下直接测试它。

我想简单地模仿我传入的记录器,但是关于模拟“Log”界面的东西似乎不起作用并且模拟像“SimpleLog”这样的类不起作用,因为这些方法是最终的。

我最终创建了一个扩展SimpleLog的匿名内部类,它覆盖了其他人委托给它的基本级“日志(级别,字符串,错误)”方法,然后只等待“级别”为5的调用

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