Frank
Frank

Reputation: 4461

Simulate File in Java

I'm trying to write unit tests for a method that takes a String filename, then opens the file and reads from it. So, to test that method, I thought about writing a file, then calling my method. However, in the build farm, it is not possible to write files arbitrarily to disk. Is there a standard way to "simulate" having a real file in my unit test?

Upvotes: 9

Views: 27041

Answers (4)

comodoro
comodoro

Reputation: 1566

If you use JUnit, there is the TemporaryFolder. Files are deleted after the test. Example given on the page:

public static class HasTempFolder {
  @Rule
  public TemporaryFolder folder= new TemporaryFolder();

  @Test
  public void testUsingTempFolder() throws IOException {
      File createdFile= folder.newFile("myfile.txt");
      File createdFolder= folder.newFolder("subfolder");
      // ...
     }
 }

However, I have also used it for testing my Android class read/write capabilities like:

    [...]
    pw = new PrintWriter(folder.getAbsolutePath() + '/' + filename);
    pw.println(data);

Upvotes: 3

Woot4Moo
Woot4Moo

Reputation: 24316

This is highly frowned upon:

The smallest amount of testable code. Often a single method/function, sans the use of other methods or classes. Fast! Thousands of unit tests can run in ten seconds or less! A unit test NEVER uses:

  • a database
  • an app server (or server of any kind)
  • file/network I/O or file system;
  • another application;
  • the console (System.out, System.err, etc.)
  • logging
  • most other classes (exceptions include DTO's, String, Integer, mocks and maybe a few others). "

Source

If you must read from a file, have a test file pre-generated that all unit tests read from. There is no need to write anything to disk.

Upvotes: -2

esaj
esaj

Reputation: 16035

I've found that Mockito and Powermock are a good combination for this. Actually there's a blog post with a sample, where the File-class's constructor is mocked for testing purposes. Here's also a small example I threw together:

public class ClassToTest
{
    public void openFile(String fileName)
    {
        File f = new File(fileName);
        if(!f.exists())
        {
            throw new RuntimeException("File not found!");
        }
    }
}

Testing with Mockito + Powermock:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassToTest.class)
public class FileTest
{
    @Test
    public void testFile() throws Exception
    {
        //Set up a mocked File-object
        File mockedFile = Mockito.mock(File.class);
        Mockito.when(mockedFile.exists()).thenReturn(true);

        //Trap constructor calls to return the mocked File-object
        PowerMockito.whenNew(File.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(mockedFile);

        //Do the test
        ClassToTest classToTest = new ClassToTest();
        classToTest.openFile("testfile.txt");

        //Verify that the File was created and the exists-method of the mock was called
        PowerMockito.verifyNew(File.class).withArguments("testfile.txt");
        Mockito.verify(mockedFile).exists();
    }
}

Upvotes: 19

Vic
Vic

Reputation: 1888

How about using mocked stream classes, which override the real ones (like BufferredReader, File) completely (meaning all methods or all methods you use)? The data can be saved as an array of bytes, for example, in some singleton, if they are to be used between different test classes.

Upvotes: 0

Related Questions