0

I am trying to write a unit test for the class:

public class ClassToTest
{
    public List<String> walk(URI path)
    {
        List<String> directories= new List<String>();

        Path share = Paths.get(path);
        try
        {
            Stream<Path> folders = Files.list(share).filter(Files::isDirectory);
            folders.forEach(Path -> {
                {
                    directories.add(Path.toUri());
                }
            });

        }
        catch (IOException | SecurityException e)
        {
           System.out.println("Exception in crawling folder:"+path.toString());
           e.printStackTrace();
        }
        return directories;
    }
}

Here is my unit test:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Files.class, ClassToTest.class })
class ClassToTestUTest
{

    @Mock
    private Path folder1;
    @Mock
    private Path folder2;
    
    private ClassToTest underTest;
    @BeforeEach
    void setUp() throws Exception
    {
        PowerMockito.mockStatic(Files.class);
    }

    @Test
    void testWalk() throws IOException
    {
        String sharepath = "\\\\ip\\Share";
        Path temp = Paths.get(sharepath);
        
        Stream<Path> folders;
        ArrayList<Path> listOfFolders = new ArrayList<Path>();
        listOfFolders.add(folder1);
        listOfFolders.add(folder2);
        folders = listOfFolders.stream();
        
        when(Files.list(any())).thenReturn(folders);
        List<String> directories= underTest.walk(temp.toUri());
        
        //Check the directories list.
    }

}

When I run this, the mock isn't working. I get a exception from the actual Files.list() method. I want to mock the (Paths.class) Paths.get() call also, but leave that for now.

Junit error:

java.lang.NullPointerException at java.nio.file.Files.provider(Files.java:97) at java.nio.file.Files.newDirectoryStream(Files.java:457) at java.nio.file.Files.list(Files.java:3451) at com.ClassToTestUTest.testWalk(ClassToTestUTest.java:51)

I found many questions related to mocking this Files class. I am using PowerMock 2.0.0 RC4 and Mockito 2.23.4.

Where am I going wrong?

Shubham
  • 98
  • 1
  • 11
  • 1
    I had a similar problem. I solved it by creating a class `FilesHelper` with a `list(Path dir)` method (non-static) that for production just calls `Files.list(dir)`. For testing this `FilesHelper` class is much easier to mock (because it's methods are non-static) and it's implementation is so simply that it is easily shown correct in a code review. – Thomas Kläger Mar 08 '21 at 11:35
  • Will try this out! Thanks! – Shubham Mar 08 '21 at 12:51
  • Were you able to solve this? Thomas' solution is what I would recommend. You want to isolate as much as possible any requirement of static, if your priority is breadth of testing, even if it isn't as "well-done" as best practices would indicate. – Compass Mar 08 '21 at 15:15
  • I am still trying this out. Having some difficulties in mocking the slf4j logger. Will update you in a day. Thanks! – Shubham Mar 09 '21 at 11:52
  • Thank you! @Compass , it worked. I guess that's the only solution! This `FilesHelper` class does not need any unit tests right? – Shubham Mar 10 '21 at 16:55
  • If it only uses static commands from core java components, it does not need unit testing. If it throws any exceptions, you should have the stubbed version throw those exceptions and it should be sufficient for coverage. – Compass Mar 11 '21 at 17:06

1 Answers1

0

Faced a similar issue. Unable to understand why java.nio.file.Files mocking failing and other final static methods are mocked.

class ClassUnderTest {
    
    public void methodUnderTest() throws IOException {
        //bla bla
        Files.lines(null/*some path*/);
        //bla bla
        return;
    }
}

Change this to

class ClassUnderTest {
    
    public void methodUnderTest() throws IOException {
        //bla bla
        filesListWrapperMethod(null/*some path*/);
        //bla bla
        return;
    }
    
    @VisibleForTesting
    Stream<Path> filesListWrapperMethod(Path path) throws IOException {
        return Files.list(path);
    }

}

Now, you can use Mockito.spy() and mock the specific APIs.

Nitin
  • 21
  • 2