Petr Kozelka

Generating temporary files in junit tests

06 July 2009 -

It is often useful to create some temporary files inside a unit test. Basically it is not a problem, because junit does not limit you in such thing; you might simply use a "current" directory to store such files, and it usually works. However, different frameworks invoking JUnit use different "current" directories, which makes it difficult to:

  • locate the temporary files for debugging purposes
  • remove them between test re-executions
  • reference static (committed) files using a relative path

I personally always use at least two such frameworks - Maven and an IDE - and I would really like to see the data always at the same place, and reference committed files using always the same relative path.
Besides that, I require that any intermediate data in my Maven modules are generated under the "target" subdirectory (or, more precisely, under ${project.build.directory}), because

  • this gives me the comfort of cleaning them as part of "mvn clean test" command without other manual specification of directories to erase
  • it does not bloat module directory structure with version-uncontrolled files.

To accomplish this, we cannot use the "current" directory; instead, we need to compute one that is always the same, and use in later in the unit test.

So it seems to be neccessary to write a method that somehow computes that "stable" directory:

public static File computeTestDataRoot()

How can it be implemented ? The key is that they execute tests from compiled classes stored in a directory, not in a jar file. We can therefore use a resource laying among these tests - which can even be one of test classes (there is always at least one, the one for which we need it), and we use it to locate root of the test classes. In Maven, it is by default "target/test-classes". To extend this nice convention, we will make the method return "target/test-data", a non-existent directory which can be used by tests to generate their stuff.

public static File computeTestDataRoot(Class anyTestClass) {
  final String clsUri = anyTestClass.getName().replace('.','/') + ".class";
  final URL url = anyTestClass.getClassLoader().getResource(clsUri);
  final String clsPath = url.getPath();
  final File root = new File(clsPath.substring(0, clsPath.length() - clsUri.length()));
  final File clsFile = new File(root, clsUri);
  return new File(root.getParentFile(), "test-data");
}

Note that we need to pass an argument to our method - the calling test class. It is a little price for getting consistent test data directory - and probably unavoidable.

Fork me on GitHub
Fork me on GitHub