我在这里读了一些关于静态方法的文章,我想我理解滥用/过度使用静态方法会导致的问题。但是我并没有真正理解为什么很难模拟静态方法。
我知道其他的模拟框架,比如PowerMock,可以做到这一点,但是为什么Mockito不能呢?
我读了这篇文章,但作者似乎虔诚地反对静态这个词,也许是我的理解能力差。
一个简单的解释/链接就好了。
我在这里读了一些关于静态方法的文章,我想我理解滥用/过度使用静态方法会导致的问题。但是我并没有真正理解为什么很难模拟静态方法。
我知道其他的模拟框架,比如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");
}
如果您需要模拟一个静态方法,这是一个糟糕设计的强烈指示器。通常,您会模拟被测试类的依赖关系。如果你的待测类引用了一个静态方法,比如java.util。例如,Math#sin——这意味着被测试的类恰好需要这种实现(例如,准确性vs.速度)。如果你想从一个具体的窦实现中抽象出来,你可能需要一个接口(你知道这是要去哪里)?