79

我的项目中有一些静态 util 方法,其中一些只是通过或抛出异常。有很多关于如何模拟具有除 void 之外的返回类型的静态方法的示例。但是我怎样才能模拟一个将 void 返回为“ doNothing()”的静态方法?

非 void 版本使用这些代码行:

@PrepareForTest(StaticResource.class)

...

PowerMockito.mockStatic(StaticResource.class);

...

Mockito.when(StaticResource.getResource("string")).thenReturn("string");

但是,如果应用于StaticResources返回void的 a ,编译将抱怨when(T)不适用于 void ...

有任何想法吗?

一种解决方法可能是让所有静态方法返回一些Boolean成功但我不喜欢解决方法。

4

4 回答 4

89

您可以像这样存根静态 void 方法:

PowerMockito.doNothing().when(StaticResource.class, "getResource", anyString());

虽然我不确定你为什么要打扰,因为当你调用mockStatic(StaticResource.class)时,StaticResource 中的所有静态方法默认都是存根的

更有用的是,您可以像这样捕获传递给StaticResource.getResource()的值:

ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
PowerMockito.doNothing().when(
               StaticResource.class, "getResource", captor.capture());

然后您可以像这样评估传递给 StaticResource.getResource 的字符串:

String resourceName = captor.getValue();
于 2013-07-02T08:10:24.717 回答
45

从 Mockito 3.4.0 开始,引入了一个实验性 API 来模拟静态方法。

以下示例代码已使用 Mockito 4.3.1 ( testImplementation("org.mockito:mockito-inline:4.3.1) 和 JUnit Jupiter 5.8.2、OpenJDK 11 进行了测试。

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import java.util.UUID;

public class StaticMockTest {

    @Test
    void showCaseStaticMock() {
        try (MockedStatic<StaticMockTest> staticMock = Mockito.mockStatic(StaticMockTest.class)) {
            staticMock.when(StaticMockTest::getUUIDValue).thenReturn("Mockito");
            Assertions.assertEquals("Mockito", StaticMockTest.getUUIDValue());
        }

        // Regular UUID
        UUID.fromString(StaticMockTest.getUUIDValue());
    }

    public static String getUUIDValue() {
        return UUID.randomUUID().toString();
    }
}

上一个答案,可能是 Mockito 1.x/2.x 和 Powermock 1.x/2.x

您可以像在真实实例上使用 Mockito 一样进行操作。例如,您可以链接存根,以下行将使第一次调用什么也不做,然后第二次和将来的调用getResources将抛出异常:

// the stub of the static method
doNothing().doThrow(Exception.class).when(StaticResource.class);
StaticResource.getResource("string");
    
// the use of the mocked static code
StaticResource.getResource("string"); // do nothing
StaticResource.getResource("string"); // throw Exception

感谢 Matt Lachman 的评论,请注意,如果在创建模拟时没有更改默认答案,则模拟默认情况下不会执行任何操作。因此写下面的代码相当于不写。

doNothing().doThrow(Exception.class).when(StaticResource.class);
    StaticResource.getResource("string");

尽管如此,对于阅读测试的同事来说,您对这个特定代码没有任何期望可能会很有趣。当然,这可以根据测试的可理解性进行调整。


顺便说一句,以我的拙见,如果您编写新代码,您应该避免模拟静态代码。在 Mockito,我们认为这通常暗示着糟糕的设计,它可能导致代码可维护性差。尽管现有的遗留代码是另一回事。

一般来说,如果你需要模拟私有或静态方法,那么这个方法做的太多了,应该外化在一个对象中,然后注入到测试对象中。

希望有帮助。

问候

于 2012-03-06T14:30:49.363 回答
19

简单来说,想象一下,如果你想在下面模拟:

StaticClass.method();

然后你写下面的代码行来模拟:

PowerMockito.mockStatic(StaticClass.class);
PowerMockito.doNothing().when(StaticClass.class);
StaticClass.method();
于 2015-05-04T12:30:54.080 回答
7

模拟一个返回 void 的静态方法,例如Fileutils.forceMKdir(File file),

示例代码:

File file =PowerMockito.mock(File.class);
PowerMockito.doNothing().when(FileUtils.class,"forceMkdir",file);
于 2016-07-07T08:09:34.377 回答