Monday, January 12, 2015

Testing with files and directories in JUnit with @Rule

Testing with Files and directories in JUnit is easy thanks to TemporaryFolder @Rule.
In JUnit rules (@Rule) can be used as an alternative or an addition to fixture setup and
cleanup methods (org.junit.Before, org.junit.After, org.junit.BeforeClass, and org.junit.AfterClass), but they are more powerful, and can be more easily shared between projects and classes.

The code to be tested

public void writeTo(String path, String content) throws IOException {
    Path target = Paths.get(path);
    if (Files.exists(target)) {
        throw new IOException("file already exists");
    }
    Files.copy(new ByteArrayInputStream(content.getBytes("UTF8")), target);
}

The above method can write a given String content to a non existing file. There are two cases that can be tested.

The Test

public class FileWriterTest {

    private FileWriter fileWriter = new FileWriter();

    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void throwsErrorWhenTargetFileExists() throws IOException {
        // arrange
        File output = temporaryFolder.newFile("output.txt");

        thrown.expect(IOException.class);
        thrown.expectMessage("file already exists");

        // act
        fileWriter.writeTo(output.getPath(), "test");
    }

    @Test
    public void writesContentToFile() throws IOException {
        // arrange
        File output = temporaryFolder.newFolder("reports")
                .toPath()
                .resolve("output.txt")
                .toFile();

        // act
        fileWriter.writeTo(output.getPath(), "test");

        // assert
        assertThat(output)
                .hasContent("test")
                .hasExtension("txt")
                .hasParent(resolvePath("reports"));
    }

    private String resolvePath(String folder) {
        return temporaryFolder
                .getRoot().toPath()
                .resolve(folder)
                .toString();
    }
}

The TemporaryFolder rule provides two method to manage files and directories: newFile and newFolder. Both method return desired object under the temporary folder created in the setup method. In case the path of the temporary folder itself is needed getRoot method of TemporaryFolder can be used.

Everything that will be added to the temp folder during tests will be automatically removed when test finishes, despite it was successful or not.

This example can be found in my unit-testing-demo project on GitHub along with many other examples.

Interested in more articles about Unit Testing on my blog? See: http://blog.codeleak.pl/search/label/unit%20testing

2 comments:

  1. Good example. I think it could be really useful for me like the template for my project. As I read in a data room review, every method should be fully optimized on the code level.

    ReplyDelete