What is the equivalent of ExternalResource and TemporaryFolder in JUnit 5?

JUnit 5.4 comes with a built-in extension to handle temporary directories in tests.

@org.junit.jupiter.api.io.TempDir annotation can be used in order to annotate class field or a parameter in a lifecycle (e.g. @BeforeEach) or test method of type File or Path.

import org.junit.jupiter.api.io.TempDir;

@Test
void writesContentToFile(@TempDir Path tempDir) throws IOException {
    // arrange
    Path output = tempDir
            .resolve("output.txt");

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

    // assert
    assertAll(
            () -> assertTrue(Files.exists(output)),
            () -> assertLinesMatch(List.of("test"), Files.readAllLines(output))
    );
}

You can read more on this in my blog post, where you will find some more examples on utilizing this built-in extension: https://blog.codeleak.pl/2019/03/temporary-directories-in-junit-5-tests.html.


The documentation for that is still in the making - see pull request #660.


Interesting article by author of TemporaryFolderExtension for JUnit5

and

his code repo on github

JUnit5.0.0 is now in general release so let's hope they turn their attention to making the experimental stuff production-ready.

Meanwhile, it seems the TemporaryFolder rule will still work with JUnit5 docs

use this:

@EnableRuleMigrationSupport
public class MyJUnit5Test {

and this:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-migrationsupport</artifactId>
    <version>5.0.0</version>
</dependency>

As far as I understood, there can be no one to one mapping from ExternalResource to an equivalent in JUnit5. The concepts just don't fit. In JUnit4, the ExternalResource basically gives you a before and an after callback, but within the rule, you have no control about what before and after actually means. You could use it with @Rule or with @ClassRule.

In JUnit5, the extension is defined to hook in specific extension points and thus the 'when' is well defined.

Another difference in concepts would be, that you can have a state in JUnit4 rules, but your JUnit5 extensions shouldn't have any state. Instead, all state should go to the execution context.

Nevertheless, here is an option I came along with, where before and after relates to each test method:

public abstract class ExternalResourceExtension 
  implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception {
        before(context);
    }

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        after(context);
    }

    protected abstract void before(ExtensionContext context);

    protected abstract void after(ExtensionContext context);
}