Static mock not working
Solution 1
Did you add
@RunWith(PowerMockRunner.class)
@PrepareForTest(Files.class)
to your junit test class containing that method?
See powermock docs, the Writing tests section.
EDIT:
Hmmm, it seems like you're doing everything right. Here's what I'm running:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Files.class)
public class TestVisitor {
public class PrintingVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
}
@Test
public void testPostVisitDirectory() throws Exception {
final Path mockedPath = Paths.get("sample path");
/* Mocking */
PowerMockito.mockStatic(Files.class);
PowerMockito.doNothing().when(Files.class, PowerMockito.method(Files.class, "delete", Path.class));
/* End Mocking */
final PrintingVisitor visitor = new PrintingVisitor();
Assert.assertEquals("The was a problem visiting the file", FileVisitResult.CONTINUE, visitor.postVisitDirectory(mockedPath, null));
}
}
If I comment out the section labeled Mocking I get the NoSuchFileException
. If I leave it, the test passes.
Perhaps post complete example which produces the error?
Solution 2
I had a similar problem using powermock 1.5.1 and the Files class and suspect it has a problem static mocking some/all jdk1.7 classes, although I don't know why. I also checked javassist version and at the time it was latest (3.18.0-GA),
I stripped my class under test to just the Files line and it still did not work. I then decided to try to mock another static class, StringUtils.chop("string"); (commons-lang3) and then my powermock test worked and I was able to force it to generate an exception from mock.
This proved to me that I'd done everything by the book and that static mocking didn't work on Files class but it did on StringUtils.
By the way I changed, both, the @PrepareForTest and the PowerMockito.mockStatic() calls to reference the correct class.
In the end I gave up mocking Files. Just a heads-up in case anyone else has the same problem.
EDIT. Got it working: I have since tried this again as I needed it in another project. There is a newer version of PowerMock out (1.5.3) which uses an updated javassist (3.18.1-GA) that fixes a bug I mentioned in my response to another comment.
I can consistently get mocking of Files
to work by adding the class under test to @PrepareForTest
as well as Files
now even if the class you are testing does not expose static methods. I hadn't needed to do this before for other static mocking. I don't know why it's needed or works differently for Files
.
Example:
public class MyTestClass {
public void justToTestMocking(Path path) throws IOException {
if (!Files.exists(path)) {
throw new IllegalArgumentException("I know there is a deleteIfExists() but I am just testing mocking");
}
Files.delete(path);
}
}
And the test below:
@RunWith(PowerMockRunner.class)
@PrepareForTest({Files.class, MyTestClass.class})
public class MyTestClassTest {
@Before
public void setUp() {
mockStatic(Files.class);
}
@Test
public void justToTestMocking_WillDeletePath() throws IOException {
Path path = mock(Path.class);
MyTestClass test = new MyTestClass();
when(Files.exists(path)).thenReturn(true);
test.justToTestMocking(path);
verifyStatic();
Files.delete(path);
}
}
Solution 3
I had a similar issue and it turns out that it was related to preparing the correct classes.
In the example above the class that was tested was already in the "prepareFor-Scope" because it was an inner class of the test class.
You have to add the classes to @PrepareForTest
that call the static methods ... and in my case these was not sufficient because the code that accessed Files.delete
was inside an anonymous class that cannot be explicitly prepared.
I named the anonymous class and added it to @PrepareForTest
and everything worked
Stainedart
Software engineer working with search engines, text mining well anything related to content!
Updated on June 09, 2022Comments
-
Stainedart almost 2 years
I have the following sample unit test that tries to mock java.nio.file.Files but this mock does not work and the code attempts to delete the sample path.
@Test public void testPostVisitDirectory() throws Exception { Path mockedPath = Paths.get("sample path"); PowerMockito.mockStatic(Files.class); PowerMockito.doNothing().when(Files.class, PowerMockito.method(Files.class, "delete", Path.class)); DeleteDirVisitor visitor = new DeleteDirVisitor(false); Assert.assertEquals("The was a problem visiting the file", FileVisitResult.CONTINUE, visitor.postVisitDirectory(mockedPath, null)); }
Any idea what is wrong?
this is the content of the method
visitor.postVisitDirectory
[...] if (e == null) { Files.delete(dir); return FileVisitResult.CONTINUE; } [...]
Thanks,
-
Stainedart about 11 yearsYes this is present. In the same class I actually have a stub
PowerMockito.stub( PowerMockito.method(Files.class, "deleteIfExists", Path.class)) .toReturn(true);
that works -
Stainedart about 11 yearsbut since the delete returns void I cannot use the same technique :(
-
Stainedart about 11 yearsMy problem might be more complicated than I though. I have successfully ran your snippet in a separated class but it does not run within my current class. Can Mocking mess things up at the test class level?
-
Tom Tresansky about 11 yearsI'm not sure what you mean. Mocking should not affect how the test class (assuming this is the one containing the
@Test
methods) functions, though the@RunWith
obviously does. -
Stainedart about 11 yearsit seems as if the @preparefortest is not behaving properly there are people that have similar issues groups.google.com/forum/?fromgroups=#!topic/powermock/…
-
Stainedart about 11 yearsIn your snippet if you remove PowerMockito.doNothing(). the test still passes because of the mockStatic so I am guessing that the mockStatic method is failing
-
Tom Tresansky about 11 yearsThe default behaviour of
mockStatic()
is to make void methods do nothing. It's probably good form to explicitly include thedoNothing()
though, to make it clear what you intend to happen to which particular methods. -
Tom Tresansky about 11 yearsThe link seems to be using PowerMock with EasyMock. I wonder how applicable it is? Did you double check all your imports to make sure its the same
Files
class in your Visitor and your Test case? -
Matt Byrne almost 11 yearsI tried adding the class to @PrepareForTest but then ran into a stackmap error, due to a bug in latest javassist: issues.jboss.org/browse/JASSIST-205 :-(. Given up again on mocking the Files class but thanks for tip!
-
mmalmeida about 6 yearsThumbs up for this. I had to add the "MyTestClass.class" to @preparefortest as well to get Files and Paths mocks to work
-
Kashyap almost 5 yearsWhen you apply
@PrepareForTest
to a class, it messes up the jacoco coverage of course. Because both instrument the class. -
Shubham about 3 yearsI am using trying to mock the Files class (Files,get()) method. But the mocking doesn't work and I get a Nullpointer exception. Any idea what might be the issue?