Skip to content

Commit

Permalink
Added support for class variable TemporaryFolder and each parameter i…
Browse files Browse the repository at this point in the history
…njection now gets its own instance of TemporaryFolder so no sharing of TemporaryFolders between tests.
  • Loading branch information
glytching committed Aug 30, 2018
1 parent 1c82668 commit d08410d
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 123 deletions.
36 changes: 35 additions & 1 deletion docs/temporaryFolder.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ This extension is engaged by adding the `@ExtendWith` annotation to a test class

#### Examples

###### Class Level TemporaryFolder
###### Instance Variable TemporaryFolder

```
@ExtendWith(TemporaryFolderExtension.class)
public class MyTest {
private TemporaryFolder temporaryFolder;
@BeforeEach
public void prepare(TemporaryFolder temporaryFolder) {
this.temporaryFolder = temporaryFolder;
}
@Test
public void canUseTemporaryFolder() throws IOException {
// use the temporary folder itself
Expand Down Expand Up @@ -56,3 +61,32 @@ public class MyTest {
}
}
```

###### Class Variable TemporaryFolder

```
@ExtendWith(TemporaryFolderExtension.class)
public class MyTest {
private static TemporaryFolder TEMPORARY_FOLDER;
@BeforeAll
public void prepare(TemporaryFolder givenTemporaryFolder) {
this.TEMPORARY_FOLDER = givenTemporaryFolder;
}
@Test
public void canUseTemporaryFolder() throws IOException {
// use the temporary folder itself
File root = TEMPORARY_FOLDER.getRoot();
// create a file within the temporary folder
File file = TEMPORARY_FOLDER.createFile("foo.txt");
assertThat(file.exists(), is(true));
// create a directory within the temporary folder
File dir = TEMPORARY_FOLDER.createDirectory("bar");
assertThat(dir.exists(), is(true));
}
}
```
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<junit.platform.version>1.0.1</junit.platform.version>
<junit.jupiter.version>5.0.1</junit.jupiter.version>
<junit.platform.version>1.2.0</junit.platform.version>
<junit.jupiter.version>5.2.0</junit.jupiter.version>
<hamcrest.version>1.3</hamcrest.version>
<mockito.version>2.7.19</mockito.version>
<random.beans.version>3.7.0</random.beans.version>

<maven.surefire.plugin.version>2.19</maven.surefire.plugin.version>
<maven.surefire.plugin.version>2.22.0</maven.surefire.plugin.version>
<maven.jar.plugin.version>3.0.2</maven.jar.plugin.version>
<maven.javadoc.plugin.version>3.0.0-M1</maven.javadoc.plugin.version>
<maven.coveralls.plugin.version>4.3.0</maven.coveralls.plugin.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
package io.github.glytching.junit.extension.folder;

import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
Expand All @@ -28,8 +30,8 @@
* with the operations which a tester may wish to invoke ({@link #createFile(String)}, {@link
* #createDirectory(String)}) and post test invocations which the associated extension will invoke.
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public class TemporaryFolder {
@SuppressWarnings({"ResultOfMethodCallIgnored", "nls"})
public class TemporaryFolder implements CloseableResource {
private static final String FILE_PREFIX = "junit";
private static final String FILE_SUFFIX = ".tmp";

Expand All @@ -53,6 +55,11 @@ public class TemporaryFolder {
}
}

@Override
public void close() throws Throwable {
destroy();
}

/**
* Returns the root folder. Exposing this offers some back compatability with JUnit4's {@code
* TemporaryFolder} so test cases which are used to invoking {@code getRoot()} on a JUnit4 rule
Expand Down Expand Up @@ -129,8 +136,10 @@ private FileVisitResult delete(Path file) throws IOException {
}
});

// delete the parent
Files.delete(rootFolder.toPath());
if (rootFolder.exists()) {
// delete the parent, if it still exists
Files.delete(rootFolder.toPath());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,22 @@
*/
package io.github.glytching.junit.extension.folder;

import org.junit.jupiter.api.extension.*;

import static io.github.glytching.junit.extension.util.ExtensionUtil.getStore;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;

/**
* The temporary folder extension provides a test with access to temporary files and directories.
* The temporary folder extension provides a {@link TemporaryFolder} which you can use to create a
* temporary file or directory for use by your test. The {@link TemporaryFolder} can be injected
* into your test or test case with either of the following approaches:
* into your test or test case with any of the following approaches:
*
* <ul>
* <li>Parameter injection into a {@code @BeforeEach} method. For example:
* <li>Instance variable injection into a {@code @BeforeEach} method. The {@link TemporaryFolder}
* will be destroyed during {@code @AfterEach} and no exception will be thrown in cases where
* the deletion fails. For example:
* <pre>
* private TemporaryFolder temporaryFolder;
*
Expand All @@ -37,17 +41,29 @@
* // ...
* }
* </pre>
* <li>Parameter injection into a {@code @Test} method. For example:
* <li>Parameter injection into a {@code @Test} method. The {@link TemporaryFolder} will be
* destroyed during {@code @AfterEach} and no exception will be thrown in cases where the
* deletion fails. For example:
* <pre>
* &#064;Test
* public void testUsingTemporaryFolder(TemporaryFolder temporaryFolder) {
* // ...
* }
* </pre>
* </ul>
* <li>Class variable injection using a {@code @BeforeAll} method. Note: in this case <b>all</b>
* tests in the test case will share the same instance of the {@code TemporaryFolder}. The
* {@link TemporaryFolder} will be destroyed after any {@code @AfterAll} method completes and
* no exception will be thrown in cases where the deletion fails. For example:
* <pre>
* private static TemporaryFolder TEMPORARY_FOLDER;
*
* <p>In both approaches the {@link TemporaryFolder} will be destroyed during {@code @AfterEach} and
* no exception will be thrown in cases where the deletion fails.
* &#064;BeforeAll
* public static void setUp(TemporaryFolder givenTemporaryFolder) {
* TEMPORARY_FOLDER = givenTemporaryFolder
* // ...
* }
* </pre>
* </ul>
*
* <p>Usage examples:
*
Expand Down Expand Up @@ -112,29 +128,9 @@
* TemporaryFolder Rule</a>
* @since 1.0.0
*/
public class TemporaryFolderExtension implements AfterEachCallback, ParameterResolver {

private static final String KEY = "temporaryFolder";
public class TemporaryFolderExtension implements ParameterResolver {

/**
* If there is a {@link TemporaryFolder} associated with the current {@code extensionContext} then
* destroy it.
*
* @param extensionContext the <em>context</em> in which the current test or container is being
* executed
*/
@Override
public void afterEach(ExtensionContext extensionContext) {
TemporaryFolder temporaryFolder =
getStore(extensionContext, this.getClass()).get(KEY, TemporaryFolder.class);
if (temporaryFolder != null) {
try {
temporaryFolder.destroy();
} catch (Exception e) {
// silent failures
}
}
}
private static final Namespace NAMESPACE = Namespace.create(TemporaryFolderExtension.class);

/**
* Does this extension support injection for parameters of the type described by the given {@code
Expand Down Expand Up @@ -168,8 +164,10 @@ public boolean supportsParameter(
public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return getStore(extensionContext, this.getClass())
.getOrComputeIfAbsent(KEY, key -> new TemporaryFolder());
return extensionContext
.getStore(NAMESPACE)
.getOrComputeIfAbsent(
parameterContext, key -> new TemporaryFolder(), TemporaryFolder.class);
}

private boolean appliesTo(Class<?> clazz) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.glytching.junit.extension.folder;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;

@ExtendWith(TemporaryFolderExtension.class)
public class TemporaryFolderExtensionBeforeAllTest {

private static TemporaryFolder TEMPORARY_FOLDER;

@BeforeAll
public static void setUp(TemporaryFolder givenTemporaryFolder) {
TEMPORARY_FOLDER = givenTemporaryFolder;
}

@AfterAll
public static void cleanUp() throws IOException {
try (Stream<Path> stream = Files.list(TEMPORARY_FOLDER.getRoot().toPath())) {
Set<String> createdFileNames =
stream.map(path -> path.toFile().getName()).collect(Collectors.toSet());

// when using a static TemporaryFolder, every test gets the same instance so in AfterAll the
// folder should contain all artifacts created by all tests in this test case
assertThat(createdFileNames.size(), is(2));
assertThat(createdFileNames, hasItem("foo.txt"));
assertThat(createdFileNames, hasItem("bar"));
}
}

@Test
public void canCreateAFile() throws IOException {
File file = TEMPORARY_FOLDER.createFile("foo.txt");
assertThat(file.exists(), is(true));
}

@Test
public void canCreateADirectory() throws IOException {
File file = TEMPORARY_FOLDER.createDirectory("bar");
assertThat(file.exists(), is(true));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import static org.hamcrest.Matchers.*;

@ExtendWith(TemporaryFolderExtension.class)
public class TemporaryFolderExtensionFieldTest {
public class TemporaryFolderExtensionBeforeEachTest {

// gather the temporary file and directory paths to facilitate assertions on (a) the distinct-ness
// of the temporary folder address supplied to each test and (b) the removal of each temporary
Expand Down

This file was deleted.

0 comments on commit d08410d

Please sign in to comment.