如何使用PowerMock和Mockito从Files.java对newDirectoryStream进行部分模拟?

时间:2019-05-19 22:19:17

标签: java mockito powermock partial-mocks

我想部分模拟Files.java newDirectoryStream静态方法。

当我使用mockStatic时,下面的示例工作得很好。不幸的是,这种方法模拟了所有静态方法。我只想模拟一个特定的对象,因此想通过调用spy方法使用部分模拟。

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;

public class FileAccess {

    public static void newDirectoryStreamWrapper(Path path) throws IOException {
        DirectoryStream<Path> paths = Files.newDirectoryStream(path);
        if (paths == null) {
            return;
        }

        for (Path p : paths) {
                // some work
        }
    }
}
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Files.class, FileAccess.class})
public class Mocking {

    private boolean called = false;

    @Rule
    public TemporaryFolder folder = new TemporaryFolder();

    @Test
    public void test() throws Exception {

        //test will pass with mockStatic instead of spy
        PowerMockito.spy(Files.class);

        Mockito
            .when(Files.newDirectoryStream(Mockito.any(Path.class)))
            .thenAnswer(new Answer<Object>() {
                @Override
                public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                    called = true;
                    return invocationOnMock.callRealMethod();
                }
            });

        Path path = folder.newFile().toPath();
        FileAccess.newDirectoryStreamWrapper(path.getParent());

        assertTrue(called);
    }
}

执行上面的代码时引发异常:

java.lang.NullPointerException
    at java.nio.file.Files.provider(Files.java:97)
    at java.nio.file.Files.newDirectoryStream(Files.java:457)
    at Mocking.test(Mocking.java:41)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
    at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

1 个答案:

答案 0 :(得分:0)

mockStatic不能模拟所有方法,它仅可以模拟所有方法。 因此,只要您没有实际模拟方法,即使在mockStatic()之后,实际方法仍然会被调用。只有在嘲笑了嘲讽行为之后显式嘲笑的方法才会以嘲笑的行为做出响应。

所以您使用mockStatic的方法是正确的。