Search code examples
javaencodingjvmpowermockito

mock java.nio.file.Paths.get do nothing but throw InvalidPathException


I have two line of code:

File file = new File("report_はな.html");
Path path = Paths.get(file.getCanonicalPath());

Is there anyway that I can mock the static method:

Paths.get(file.getCanonicalPath());

And only throw the exception InvalidPathException?

I tried the powermockito, but it seems does not working

PowerMockito.mockStatic(Paths.class);
PowerMockito.doReturn(null).doThrow(new InvalidPathException("","")).when(Paths.class);

The whole idea is I am trying to reproduce the bug that Under the English Mac, the Mac default encoding setting is US-ASCII, which Path path = Paths.get("report_はな.html"); will throw this InvalidPathException.


Solution

  • As documented here, you have to jump through some hoops to mock "system" classes, i.e. classes loaded by the system classloader.

    Specifically, whereas in a normal PowerMock test the @PrepareForTest() annotation identifies the class whose static methods you want to mock, in a "system" PowerMock test the annotation needs to identify the class that calls the static methods (usually the class under test).

    For instance, say we have the following class:

    public class Foo {
        public static Path doGet(File f) throws IOException {
            try {
                return Paths.get(f.getCanonicalPath());
            } catch (InvalidPathException e) {
                return null;
            }
        }
    }
    

    We want to test that this class does in fact return null if Paths.get() throws an InvalidPathException. To test this, we write:

    @RunWith(PowerMockRunner.class)  // <- important!
    @PrepareForTest(Foo.class)       // <- note: Foo.class, NOT Paths.class
    public class FooTest {
        @Test
        public void doGetReturnsNullForInvalidPathException() throws IOException {
            // Enable static mocking on Paths
            PowerMockito.mockStatic(Paths.class);
    
            // Make Paths.get() throw IPE for all arguments
            Mockito.when(Paths.get(any(String.class)))
              .thenThrow(new InvalidPathException("", ""));
    
            // Assert that method invoking Paths.get() returns null
            assertThat(Foo.doGet(new File("foo"))).isNull();
        }
    }
    

    Note: I wrote Paths.get(any(String.class)) but you could mock something more specific if need be, e.g. Paths.get("foo")) or Paths.get(new File("report_はな.html").getCanonicalPath()).