Don’t Clean Up After Tests with RunListener.testRunFinished()
, Add a Shutdown Hook Instead
Recently, while I was writing some tests which require a lot of temporary files, I ran into a problem: my tests never cleaned up the temporary files.
$ mvn test
…
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
Creating temp file for all tests: /tmp/example-junit-test-1057360590374847337.txt
[INFO] Running example.junit.ExampleTest1
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.071 s - in example.junit.ExampleTest1
[INFO] Running example.junit.ExampleTest3
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in example.junit.ExampleTest3
[INFO] Running example.junit.ExampleTest2
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in example.junit.ExampleTest2
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
…
$ ls /tmp/example-junit-test-*.txt
…
/tmp/example-junit-test-1057360590374847337.txt
I needed to clean up the temporary files after all the tests had run. Since each test needed to reside in a separate Java class, I could not rely on an @AfterClass
method for clean up. So I added a RunListener
.testRunFinished()
method to delete the files:
@Override
public void testRunFinished(Result result) throws Exception {
// Clean up temp files.
}
This worked correctly, and the temp files were deleted after all the tests ran.
$ mvn test
…
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
Creating temp file for all tests: /tmp/example-junit-test-6810591342693798561.txt
[INFO] Running example.junit.ExampleTest1
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.065 s - in example.junit.ExampleTest1
[INFO] Running example.junit.ExampleTest3
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in example.junit.ExampleTest3
[INFO] Running example.junit.ExampleTest2
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in example.junit.ExampleTest2
Deleting temp file for all tests: /tmp/example-junit-test-6810591342693798561.txt
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
…
$ ls /tmp/example-junit-test-*.txt
…
ls: cannot access /tmp/example-junit-test-*.txt: No such file or directory
But then I ran into a different problem: when I killed the tests early with [Ctrl]
+ [C]
, the files were never deleted.
$ mvn test
…
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
Creating temp file for all tests: /tmp/example-junit-test-5067607655485865565.txt
[INFO] Running example.junit.ExampleTest1
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.058 s - in example.junit.ExampleTest1
[INFO] Running example.junit.ExampleTest3
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in example.junit.ExampleTest3
[INFO] Running example.junit.ExampleTest2
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in example.junit.ExampleTest2
^C
…
$ ls /tmp/example-junit-test-*.txt
…
/tmp/example-junit-test-5067607655485865565.txt
The solution was simple: instead of using RunListener.testRunFinished()
, I needed to add a shutdown hook:
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// Clean up temp files.
}));
Now the shutdown hook would ensure the temporary files were deleted whether the build process was killed prematurely or not!
$ mvn test
…
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
Creating temp file for all tests: /tmp/example-junit-test-2853721297857519700.txt
[INFO] Running example.junit.ExampleTest1
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.059 s - in example.junit.ExampleTest1
[INFO] Running example.junit.ExampleTest3
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 s - in example.junit.ExampleTest3
[INFO] Running example.junit.ExampleTest2
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in example.junit.ExampleTest2
^C
…
$ ls /tmp/example-junit-test-*.txt
…
ls: cannot access /tmp/example-junit-test-*.txt: No such file or directory
Unless you must take action based on the result of all the tests, don’t use RunListener.testRunFinished()
. Instead use Runtime.addShutdownHook()
to ensure that your clean up occurs even if the build/test process is killed prematurely.