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

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

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

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


当前回答

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

其他回答

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

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

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

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

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

作为对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");
}

Mockito[3.4.0]可以模拟静态方法!

Replace mockito-core dependency with mockito-inline:3.4.0. Class with static method: class Buddy { static String name() { return "John"; } } Use new method 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 replaces the static method within the try block only.