Home > Deldorado > Generating temporary files in junit tests

Generating temporary files in junit tests

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.

Categories: Deldorado Tags: , ,
  • http://kaczanowscy.pl/tomek Tomek

    take a look at TemporaryFolder in JUnit (since 4.7), e.g. http://weblogs.java.net/blog/johnsmart/archive/2009/09/29/working-temporary-files-junit-47

    I am not aware if TestNG also offers such feature

  • Petr Kozelka

    thanks for the tip, it seems to cover some important cases – when I want the files to disappear after the test I would prefer a standard solution like this one

  • etienne_sf

    Hi,

    Thanks for this very useful tip. I used it with success, for the jupload project, available on sourceforge.

    A note:
    I changed the line ‘final String clsPath = url.getPath();’ to:
    final String clsPath = url.getPath().replaceAll(“%20″, ” “);

    This allows working with pathes containing spaces.

    Etienne

  • http://www.classactionpl.com/ Christopher Hunt

    I find just using the temporary folder path system variable suffices e.g.:

    String filename = “some.dat”;
    String filepath = System.getProperty(“java.io.tmpdir”);
    String fullFilePath = filepath + filename;

    I generally then create a file and use a try/finally block to remove the file when the test is done.

  • Petr Kozelka

    That’s correct – this is definitely simpler solution.

    However, what I like on the suggested one is, that temporary files used by the module are “inside” it, which has some advantages, like:
    - next “mvn clean install” command removes them so you don’t have to take care of it
    - they are naturally bound to the right module and its last build; in your case, you either need to hardcode the name which may cause problems (at least it should be deleted before using), or generate a random dir – then you must go to log and see which one was used

    So, the technique you suggest is valid, but I prefer using it only on “manually” started tests, not for tests that are executed inside a continuous integration system

  • Scott Carey

    Just pass ${project.build.directory} in as a property to your tests via surefire systemPropertyValues, avoiding the classloader stuff.

    http://maven.apache.org/plugins/maven-surefire-plugin/examples/system-properties.html

    Then you don’t need to pass in a class, and your test helper method can be simpler.

  • Petr Kozelka

    @Scott Carey
    yes but that is not good for running the tests from your IDE then – unless it calls Maven for junit testing which is not usual.
    But you are right, this makes the whole thing a bit simpler on modules where you don’t care about IDEs.

  • http://www.google.com/profiles/davestaab Dave S

    Thanks for sharing. This was exactly what I needed.

blog comments powered by Disqus