0

I would like to partially mock Files.java newDirectoryStream static method.

Example below work perfectly fine when I use mockStatic. Unfortunately this approach mock all static methods. I would like to mock only one specific so wanted to use partial mocking through calling spy method.

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);
    }
}

Exception thrown while executing code above:

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)
Adrian
  • 71
  • 1
  • 12

1 Answers1

0

mockStatic does not mock all methods, it only enables mocking for all methods. So as long as you do not actually mock a methods, the real methods still get called even after mockStatic(). Only methods that are explicitly mocked after mockStatic will respond with the mocked behavior.

So your approach with mockStatic is correct.

tkruse
  • 10,222
  • 7
  • 53
  • 80