Static mock not working

10,746

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.deletewas inside an anonymous class that cannot be explicitly prepared.

I named the anonymous class and added it to @PrepareForTest and everything worked

Share:
10,746
Stainedart
Author by

Stainedart

Software engineer working with search engines, text mining well anything related to content!

Updated on June 09, 2022

Comments

  • Stainedart
    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
    Stainedart about 11 years
    Yes 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
    Stainedart about 11 years
    but since the delete returns void I cannot use the same technique :(
  • Stainedart
    Stainedart about 11 years
    My 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
    Tom Tresansky about 11 years
    I'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
    Stainedart about 11 years
    it seems as if the @preparefortest is not behaving properly there are people that have similar issues groups.google.com/forum/?fromgroups=#!topic/powermock/…
  • Stainedart
    Stainedart about 11 years
    In 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
    Tom Tresansky about 11 years
    The default behaviour of mockStatic() is to make void methods do nothing. It's probably good form to explicitly include the doNothing() though, to make it clear what you intend to happen to which particular methods.
  • Tom Tresansky
    Tom Tresansky about 11 years
    The 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
    Matt Byrne almost 11 years
    I 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
    mmalmeida about 6 years
    Thumbs up for this. I had to add the "MyTestClass.class" to @preparefortest as well to get Files and Paths mocks to work
  • Kashyap
    Kashyap almost 5 years
    When you apply @PrepareForTest to a class, it messes up the jacoco coverage of course. Because both instrument the class.
  • Shubham
    Shubham about 3 years
    I 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?