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)
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.