Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static mock not working

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,

like image 893
Stainedart Avatar asked Feb 19 '13 20:02

Stainedart


People also ask

Why does Mockito not mock static methods?

Mockito allows us to create mock objects. Since static method belongs to the class, there is no way in Mockito to mock static methods. However, we can use PowerMock along with Mockito framework to mock static methods.

How do you do a static mock method?

Mocking a No Argument Static Method 0, we can use the Mockito. mockStatic(Class<T> classToMock) method to mock invocations to static method calls. This method returns a MockedStatic object for our type, which is a scoped mock object.

Can you mock a static field?

Static methods can be mocked in a similar way as we saw for the private methods. When a method under test, involves using a static method from the same class (or from a different class), we will need to include that class in prepareForTest annotation before the Test (or on the test class).

Can we mock static methods using MOQ?

You can use Moq to mock non-static methods but it cannot be used to mock static methods. Although static methods cannot be mocked easily, there are a few ways to mock static methods. You can take advantage of the Moles or Fakes framework from Microsoft to mock static method calls.


2 Answers

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);
    }
}
like image 104
Matt Byrne Avatar answered Sep 28 '22 01:09

Matt Byrne


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?

like image 35
Tom Tresansky Avatar answered Sep 28 '22 00:09

Tom Tresansky