Skip to content

Commit

Permalink
Add support for private TempDir fields
Browse files Browse the repository at this point in the history
Resolves junit-team#2687.
  • Loading branch information
marcphilipp authored and runningcode committed Feb 15, 2023
1 parent f36e25f commit aee3ce3
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,13 @@ on GitHub.
temporary directory. To revert to the old behavior of using a single temporary directory
for the entire test class or method (depending on which level the annotation is used),
you can set the `junit.jupiter.tempdir.scope` configuration parameter to `per_context`.
* `@TempDir` cleanup resets readable and executable permissions of the root temporary
directory and any contained directories instead of failing to delete them.
* `@TempDir` fields may now be private.
* New `named()` static factory method in the `Named` interface that serves as an _alias_
for `Named.of()`. `named()` is intended to be used via `import static`.
* New `class` URI scheme for dynamic test sources. This allows tests to be located using
the information available in a `StackTraceElement`.
* `@TempDir` cleanup resets readable and executable permissions of the root temporary
directory and any contained directories instead of failing to delete them.
* New `assertThrowsExactly` method which is a more strict version of `assertThrows`
that allows you to assert that the thrown exception has the exact specified class.
* New `autoCloseArguments` attribute in `@ParameterizedTest` to close `AutoCloseable`
Expand Down
8 changes: 4 additions & 4 deletions documentation/src/docs/asciidoc/user-guide/writing-tests.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2183,9 +2183,9 @@ can improve and eventually <<api-evolution, promote>> this feature.

The built-in `{TempDirectory}` extension is used to create and clean up a temporary
directory for an individual test or all tests in a test class. It is registered by
default. To use it, annotate a non-private field of type `java.nio.file.Path` or
`java.io.File` with `{TempDir}` or add a parameter of type `java.nio.file.Path` or
`java.io.File` annotated with `@TempDir` to a lifecycle method or test method.
default. To use it, annotate a field of type `java.nio.file.Path` or `java.io.File` with
`{TempDir}` or add a parameter of type `java.nio.file.Path` or `java.io.File` annotated
with `@TempDir` to a lifecycle method or test method.

For example, the following test declares a parameter annotated with `@TempDir` for a
single test method, creates and writes to a file in the temporary directory, and checks
Expand All @@ -2212,7 +2212,7 @@ please note that this option is deprecated and will be removed in a future relea

`@TempDir` is not supported on constructor parameters. If you wish to retain a single
reference to a temp directory across lifecycle methods and the current test method, please
use field injection, by annotating a non-private instance field with `@TempDir`.
use field injection by annotating an instance field with `@TempDir`.

The following example stores a _shared_ temporary directory in a `static` field. This
allows the same `sharedTempDir` to be used in all lifecycle methods and test methods of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
import org.junit.jupiter.api.extension.ParameterResolutionException;

/**
* {@code @TempDir} can be used to annotate a non-private field in a test class
* or a parameter in a lifecycle method or test method of type {@link Path} or
* {@code @TempDir} can be used to annotate a field in a test class or a
* parameter in a lifecycle method or test method of type {@link Path} or
* {@link File} that should be resolved into a temporary directory.
*
* <p>Please note that {@code @TempDir} is not supported on constructor
* parameters. Please use field injection instead, by annotating a non-private
* instance field with {@code @TempDir}.
* parameters. Please use field injection instead by annotating an instance
* field with {@code @TempDir}.
*
* <h3>Creation</h3>
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import static java.util.stream.Collectors.joining;
import static org.junit.jupiter.engine.config.JupiterConfiguration.TEMP_DIR_SCOPE_PROPERTY_NAME;
import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields;
import static org.junit.platform.commons.util.ReflectionUtils.isPrivate;
import static org.junit.platform.commons.util.ReflectionUtils.makeAccessible;

import java.io.File;
Expand Down Expand Up @@ -99,7 +98,7 @@ private void injectFields(ExtensionContext context, Object testInstance, Class<?
Predicate<Field> predicate) {

findAnnotatedFields(testClass, TempDir.class, predicate).forEach(field -> {
assertValidFieldCandidate(field);
assertSupportedType("field", field.getType());
try {
makeAccessible(field).set(testInstance, getPathOrFile(field, field.getType(), context));
}
Expand All @@ -109,13 +108,6 @@ private void injectFields(ExtensionContext context, Object testInstance, Class<?
});
}

private void assertValidFieldCandidate(Field field) {
assertSupportedType("field", field.getType());
if (isPrivate(field)) {
throw new ExtensionConfigurationException("@TempDir field [" + field + "] must not be private.");
}
}

/**
* Determine if the {@link Parameter} in the supplied {@link ParameterContext}
* is annotated with {@link TempDir @TempDir}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,24 +292,6 @@ void resolvesSeparateTempDirWhenAnnotationIsUsedOnAfterAllMethodParameterOnly()
@TestMethodOrder(OrderAnnotation.class)
class Failures {

@Test
@DisplayName("when @TempDir is used on private static field")
@Order(10)
void onlySupportsNonPrivateInstanceFields() {
var results = executeTestsForClass(AnnotationOnPrivateStaticFieldTestCase.class);

assertSingleFailedContainer(results, ExtensionConfigurationException.class, "must not be private");
}

@Test
@DisplayName("when @TempDir is used on private instance field")
@Order(11)
void onlySupportsNonPrivateStaticFields() {
var results = executeTestsForClass(AnnotationOnPrivateInstanceFieldTestCase.class);

assertSingleFailedTest(results, ExtensionConfigurationException.class, "must not be private");
}

@Test
@DisplayName("when @TempDir is used on static field of an unsupported type")
@Order(20)
Expand Down Expand Up @@ -368,6 +350,29 @@ void doesNotSupportTempDirAnnotationOnConstructorParameterWithTestInstancePerCla

}

@Nested
@DisplayName("supports @TempDir")
@TestMethodOrder(OrderAnnotation.class)
class PrivateFields {

@Test
@DisplayName("on private static field")
@Order(10)
void supportsPrivateInstanceFields() {
executeTestsForClass(AnnotationOnPrivateStaticFieldTestCase.class).testEvents()//
.assertStatistics(stats -> stats.started(1).succeeded(1));
}

@Test
@DisplayName("on private instance field")
@Order(11)
void supportsPrivateStaticFields() {
executeTestsForClass(AnnotationOnPrivateInstanceFieldTestCase.class).testEvents()//
.assertStatistics(stats -> stats.started(1).succeeded(1));
}

}

private static void assertSingleFailedContainer(EngineExecutionResults results, Class<? extends Throwable> clazz,
String message) {

Expand Down Expand Up @@ -526,6 +531,7 @@ static class AnnotationOnPrivateInstanceFieldTestCase {

@Test
void test() {
assertTrue(Files.exists(tempDir));
}

}
Expand All @@ -538,6 +544,7 @@ static class AnnotationOnPrivateStaticFieldTestCase {

@Test
void test() {
assertTrue(Files.exists(tempDir));
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,24 +191,6 @@ void canBeUsedViaStaticFieldInsideNestedTestClasses() {
@TestMethodOrder(OrderAnnotation.class)
class Failures {

@Test
@DisplayName("when @TempDir is used on private static field")
@Order(10)
void onlySupportsNonPrivateInstanceFields() {
var results = executeTestsForClass(AnnotationOnPrivateStaticFieldTestCase.class);

assertSingleFailedContainer(results, ExtensionConfigurationException.class, "must not be private");
}

@Test
@DisplayName("when @TempDir is used on private instance field")
@Order(11)
void onlySupportsNonPrivateStaticFields() {
var results = executeTestsForClass(AnnotationOnPrivateInstanceFieldTestCase.class);

assertSingleFailedTest(results, ExtensionConfigurationException.class, "must not be private");
}

@Test
@DisplayName("when @TempDir is used on static field of an unsupported type")
@Order(20)
Expand Down Expand Up @@ -267,6 +249,29 @@ void doesNotSupportTempDirAnnotationOnConstructorParameterWithTestInstancePerCla

}

@Nested
@DisplayName("supports @TempDir")
@TestMethodOrder(OrderAnnotation.class)
class PrivateFields {

@Test
@DisplayName("on private static field")
@Order(10)
void supportsPrivateInstanceFields() {
executeTestsForClass(AnnotationOnPrivateStaticFieldTestCase.class).testEvents()//
.assertStatistics(stats -> stats.started(1).succeeded(1));
}

@Test
@DisplayName("on private instance field")
@Order(11)
void supportsPrivateStaticFields() {
executeTestsForClass(AnnotationOnPrivateInstanceFieldTestCase.class).testEvents()//
.assertStatistics(stats -> stats.started(1).succeeded(1));
}

}

private static void assertSingleFailedContainer(EngineExecutionResults results, Class<? extends Throwable> clazz,
String message) {

Expand Down Expand Up @@ -306,6 +311,7 @@ static class AnnotationOnPrivateInstanceFieldTestCase {

@Test
void test() {
assertTrue(Files.exists(tempDir));
}

}
Expand All @@ -318,6 +324,7 @@ static class AnnotationOnPrivateStaticFieldTestCase {

@Test
void test() {
assertTrue(Files.exists(tempDir));
}

}
Expand Down

0 comments on commit aee3ce3

Please sign in to comment.