我在这里读了一些关于静态方法的文章,我想我理解滥用/过度使用静态方法会导致的问题。但是我并没有真正理解为什么很难模拟静态方法。
我知道其他的模拟框架,比如PowerMock,可以做到这一点,但是为什么Mockito不能呢?
我读过这篇文章,但作者似乎虔诚地反对static这个词,也许是我理解能力差。
static
一个简单的解释/链接就好了。
在某些情况下,静态方法可能很难测试,特别是当它们需要被模拟时,这就是大多数模拟框架不支持它们的原因。我发现这博客文章在确定如何模拟静态方法和类方面非常有用。
我认为原因可能是模拟对象库通常通过在运行时动态创建类来创建模拟(使用cglib)。这意味着它们要么在运行时实现接口(如果我没有弄错的话,这就是EasyMock所做的),要么从类继承到mock(如果我没有弄错的话,这就是Mockito所做的)。这两种方法都不适用于静态成员,因为您不能使用继承重写它们。
模拟静态的唯一方法是在运行时修改一个类的字节码,我认为这比继承要复杂一些。
这是我的猜测,无论如何……
如果您需要模拟一个静态方法,这是一个糟糕设计的强烈指示器。通常,您会模拟被测试类的依赖关系。如果你的待测类引用了一个静态方法,比如java.util。例如,Math#sin——这意味着被测试的类恰好需要这种实现(例如,准确性vs.速度)。如果你想从一个具体的窦实现中抽象出来,你可能需要一个接口(你知道这是要去哪里)?
我真的认为,如果您也需要模拟静态方法,这就是代码的味道。
PS:私有方法也是如此。我认为测试不应该知道私有方法的细节。如果一个类非常复杂,以至于它倾向于模拟私有方法,这可能是拆分该类的标志……
Mockito返回对象,但静态意味着“类级别,而不是对象级别”,因此Mockito将为静态提供空指针异常。
< a href = " https://asolntsev.github。io/ zh /2020/07/11/ Mockito -static-methods/" rel="noreferrer">Mockito[3.4.0]可以模拟静态方法!< / >
用mockito-inline:3.4.0。替换mockito-core依赖项
mockito-inline:3.4.0
mockito-core
类静态方法:
class Buddy { static String name() { return "John"; } }
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块中的静态方法。
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"); }