TestFS

TestFS is a file system test support library.

License

License

Categories

Categories

Net
GroupId

GroupId

net.gredler
ArtifactId

ArtifactId

test-fs
Last Version

Last Version

0.2
Release Date

Release Date

Type

Type

jar
Description

Description

TestFS
TestFS is a file system test support library.
Project URL

Project URL

https://github.com/gredler/test-fs
Source Code Management

Source Code Management

https://github.com/gredler/test-fs

Download test-fs

How to add to project

<!-- https://jarcasting.com/artifacts/net.gredler/test-fs/ -->
<dependency>
    <groupId>net.gredler</groupId>
    <artifactId>test-fs</artifactId>
    <version>0.2</version>
</dependency>
// https://jarcasting.com/artifacts/net.gredler/test-fs/
implementation 'net.gredler:test-fs:0.2'
// https://jarcasting.com/artifacts/net.gredler/test-fs/
implementation ("net.gredler:test-fs:0.2")
'net.gredler:test-fs:jar:0.2'
<dependency org="net.gredler" name="test-fs" rev="0.2">
  <artifact name="test-fs" type="jar" />
</dependency>
@Grapes(
@Grab(group='net.gredler', module='test-fs', version='0.2')
)
libraryDependencies += "net.gredler" % "test-fs" % "0.2"
[net.gredler/test-fs "0.2"]

Dependencies

test (1)

Group / Artifact Type Version
junit : junit jar 4.12

Project Modules

There are no modules declared in this project.

TestFS License Maven Central Build Status

// Give me access to the file system...
FileSystem fs = new TestFS()
    // ... but pretend that these files doesn't exist, even if they do
    .removingFiles("config/user.properties", "config/startup.properties")
    // ... and pretend that this file exists and contains my sample license
    .addingFile("user1.license", "src/test/resources/sample.license", Permissions.RWX)
    // ... and pretend this file exists, contains my sample license, but isn't readable
    .addingFile("user2.license", "src/test/resources/sample.license", Permissions._WX)
    // ... and I'm sure this file exists, but I want to pretend that it isn't writable
    .alteringPermissions("src/test/resources/input.xml", Permissions.R_X)
    // ... and please throw an IOException if I try to read the contents of this file
    .throwingExceptionOnRead("/opt/app/config.xml")
    // ... and please throw an IOException if I try to write to this file
    .throwingExceptionOnWrite("/opt/app/output.log")
    // ... k thanks!
    .create();

##Why?

Static state is bad. You know it, and you try to avoid it. But sometimes it's sneaky. That innocent-looking new Date() call is going behind your back and talking to the system clock. Similarly, those new File(myPath) calls are talking to the global file system. Java 8 introduced the Clock abstraction to help with the date situation, but what about your file-dependent code?

Java 7 added a new file system abstraction that can be used to eliminate this particular flavor of static state. FileSystemProviders are associated with a URI scheme and provide access to FileSystems, which themselves provide access to file Paths and other file system attributes and services. These Paths can then be used to read from and write to the associated file system, using the Files utility class.

If you provide your file-dependent code with a FileSystem instance through which to interact with the file system, you remove this implicit global state, and open the door to the possibility of using one FileSystem at runtime and a different FileSystem during testing. But what FileSystem should you use during testing?

One option is Google's Jimfs, an in-memory FileSystem implementation that allows you to create a virtual file system according to your test needs. Jimfs is fast and powerful, but can require a significant amount of boilerplate code to set up (and shut down) correctly. It also doesn't support some important features like file permissions.

TestFS is another alternative, and takes a slightly different approach: rather than providing a custom file system that needs to be set up from scratch and then cleaned up after your tests, it's a thin wrapper around the default file system, with extra functionality that allows you to selectively hide files, add simulated files, or simulate different permissions on existing files. This alternative approach, which allows you to start with the default file system and then tweak its behavior without modifying the actual file system, may in some cases be a better fit than the Jimfs approach of starting with a blank slate.

##Example

As an example, take the following application code:

public void checkLicense() {
    File license = new File("user.license");
    if (!license.exists()) {
        throw new LicenseException(license.getPath() + "' does not exist.");
    } else if (!license.canRead()) {
        throw new LicenseException(license.getPath() + "' cannot be read.");
    } else {
        checkLicense(new FileInputStream(license));
    }
}

checkLicense();

Testing this code will likely involve the creation of temporary files that need to be cleaned up after your tests:

@Test
public void testCheckLicenseSuccess() throws IOException {
    File src = new File("src/test/resources/sample.license");
    File dest = new File("user.license");
    FileUtils.copyFile(src, dest);
    try {
        instance.checkLicense();
    } finally {
        FileUtils.deleteQuietly(dest);
    }
}

However, the application code can be refactored as follows:

public void checkLicense(FileSystem fs) {
    Path license = fs.getPath("user.license");
    if (!Files.exists(license)) {
        throw new LicenseException(license.getPath() + "' does not exist.");
    } else if (!Files.isReadable(license)) {
        throw new LicenseException(license.getPath() + "' cannot be read.");
    } else {
        checkLicense(Files.newInputStream(license));
    }
}

checkLicense(FileSystems.getDefault());

You can then use TestFS to easily simulate different test scenarios:

@Test
public void testCheckLicenseSuccess() {
    FileSystem fs = new TestFS()
        .addingFile("user.license", "src/test/resources/sample.license")
        .create();
    instance.checkLicense(fs);
}

@Test(expected = LicenseException.class)
public void testCheckLicenseUnreadable() {
    FileSystem fs = new TestFS()
        .addingFile("user.license", "src/test/resources/sample.license", Permissions._WX)
        .create();
    instance.checkLicense(fs);
}

@Test(expected = LicenseException.class)
public void testCheckLicenseInexistent() {
    FileSystem fs = new TestFS()
        .removingFiles("user.license")
        .create();
    instance.checkLicense(fs);
}

See the JavaDoc of the TestFS class for the full API documentation.

Versions

Version
0.2
0.1