为什么Mockito不模仿静态方法?

我在这里读了一些关于静态方法的文章,我想我理解滥用/过度使用静态方法会导致的问题。但是我并没有真正理解为什么很难模拟静态方法。

我知道其他的模拟框架,比如PowerMock,可以做到这一点,但是为什么Mockito不能呢?

我读过这篇文章,但作者似乎虔诚地反对static这个词,也许是我理解能力差。

一个简单的解释/链接就好了。

230056 次浏览

在某些情况下,静态方法可能很难测试,特别是当它们需要被模拟时,这就是大多数模拟框架不支持它们的原因。我发现博客文章在确定如何模拟静态方法和类方面非常有用。

我认为原因可能是模拟对象库通常通过在运行时动态创建类来创建模拟(使用cglib)。这意味着它们要么在运行时实现接口(如果我没有弄错的话,这就是EasyMock所做的),要么从类继承到mock(如果我没有弄错的话,这就是Mockito所做的)。这两种方法都不适用于静态成员,因为您不能使用继承重写它们。

模拟静态的唯一方法是在运行时修改一个类的字节码,我认为这比继承要复杂一些。

这是我的猜测,无论如何……

如果您需要模拟一个静态方法,这是一个糟糕设计的强烈指示器。通常,您会模拟被测试类的依赖关系。如果你的待测类引用了一个静态方法,比如java.util。例如,Math#sin——这意味着被测试的类恰好需要这种实现(例如,准确性vs.速度)。如果你想从一个具体的窦实现中抽象出来,你可能需要一个接口(你知道这是要去哪里)?

我真的认为,如果您也需要模拟静态方法,这就是代码的味道。

  • 访问公共功能的静态方法?->使用一个单例实例并注入
  • 第三方代码?->将它包装到你自己的接口/委托中(如果有必要,也将它设置为单例)
唯一一次对我来说,这似乎是多余的,像番石榴,但你不应该嘲笑这种无论如何,因为这是逻辑的一部分…(Iterables.transform(..))
这样你自己的代码就可以保持干净,你可以以干净的方式模拟出所有的依赖关系,并且你有一个针对外部依赖关系的反破坏层。 我在实践中见过PowerMock,我们需要它的所有类都设计得很糟糕。此外,PowerMock的集成有时会导致严重的问题
https://code.google.com/p/powermock/issues/detail?id=355) < / p >

PS:私有方法也是如此。我认为测试不应该知道私有方法的细节。如果一个类非常复杂,以至于它倾向于模拟私有方法,这可能是拆分该类的标志……

Mockito返回对象,但静态意味着“类级别,而不是对象级别”,因此Mockito将为静态提供空指针异常。

< a href = " https://asolntsev.github。io/ zh /2020/07/11/ Mockito -static-methods/" rel="noreferrer">Mockito[3.4.0]可以模拟静态方法!< / >

  1. mockito-inline:3.4.0替换mockito-core依赖项

  2. 类静态方法:

    class Buddy {
    static String name() {
    return "John";
    }
    }
    
  3. 使用新方法Mockito.mockStatic():

    @Test
    void lookMomICanMockStaticMethods() {
    assertThat(Buddy.name()).isEqualTo("John");
    
    
    try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
    theMock.when(Buddy::name).thenReturn("Rafael");
    assertThat(Buddy.name()).isEqualTo("Rafael");
    }
    
    
    assertThat(Buddy.name()).isEqualTo("John");
    }
    

    Mockito只替换try块中的静态方法。

作为Gerold Broser的回答的补充,这里有一个带有参数的模拟静态方法的例子:

class Buddy {
static String addHello(String name) {
return "Hello " + name;
}
}


...


@Test
void testMockStaticMethods() {
assertThat(Buddy.addHello("John")).isEqualTo("Hello John");


try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
theMock.when(() -> Buddy.addHello("John")).thenReturn("Guten Tag John");
assertThat(Buddy.addHello("John")).isEqualTo("Guten Tag John");
}


assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
}