diff --git a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java index 07bf6d063d77..62153c99bf81 100644 --- a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java +++ b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java @@ -122,45 +122,25 @@ public void reportEntriesArePublishedToExecutionContext() { } @Test - public void storingAttributesWithDefaultNamespace() { + public void usingStore() { MethodTestDescriptor methodTestDescriptor = methodDescriptor(); ClassTestDescriptor classTestDescriptor = outerClassDescriptor(methodTestDescriptor); ExtensionContext parentContext = new ClassBasedContainerExtensionContext(null, null, classTestDescriptor); MethodBasedTestExtensionContext childContext = new MethodBasedTestExtensionContext(parentContext, null, methodTestDescriptor, new OuterClass()); - childContext.put("a key", "a value"); - assertEquals("a value", childContext.get("a key")); + ExtensionContext.Store store = childContext.getStore(); - assertEquals("other value", childContext.getOrComputeIfAbsent("other key", key -> "other value")); + store.put("a key", "a value"); + assertEquals("a value", store.get("a key")); - childContext.remove("a key"); - assertNull(childContext.get("a key")); + assertEquals("other value", store.getOrComputeIfAbsent("other key", key -> "other value")); - parentContext.put("parent key", "parent value"); - assertEquals("parent value", childContext.get("parent key")); - } - - @Test - public void storingAttributesWithNamespace() { - MethodTestDescriptor methodTestDescriptor = methodDescriptor(); - ClassTestDescriptor classTestDescriptor = outerClassDescriptor(methodTestDescriptor); - ExtensionContext parentContext = new ClassBasedContainerExtensionContext(null, null, classTestDescriptor); - MethodBasedTestExtensionContext childContext = new MethodBasedTestExtensionContext(parentContext, null, - methodTestDescriptor, new OuterClass()); - - String namespace = "a namespace"; - - childContext.put("a key", "a value", namespace); - assertEquals("a value", childContext.get("a key", namespace)); - - assertEquals("other value", childContext.getOrComputeIfAbsent("other key", key -> "other value"), namespace); - - childContext.remove("a key", namespace); - assertNull(childContext.get("a key", namespace)); + assertEquals("a value", store.remove("a key")); + assertNull(store.get("a key")); - parentContext.put("parent key", "parent value", namespace); - assertEquals("parent value", childContext.get("parent key", namespace)); + store.put("parent key", "parent value"); + assertEquals("parent value", store.get("parent key")); } private ClassTestDescriptor nestedClassDescriptor() { diff --git a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java index 7bd154a121e0..0b2efd466d1d 100644 --- a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java +++ b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java @@ -15,7 +15,7 @@ import org.junit.gen5.api.BeforeEach; import org.junit.gen5.api.Nested; import org.junit.gen5.api.Test; -import org.junit.gen5.engine.junit5.descriptor.ExtensionValuesStore.Namespace; +import org.junit.gen5.api.extension.ExtensionContext.*; /** * Microtests for {@link ExtensionValuesStore} @@ -29,6 +29,8 @@ class ExtensionValuesStoreTests { private Object value = createObject("value"); + private Namespace namespace = Namespace.of("ns"); + @BeforeEach void initializeStore() { parentStore = new ExtensionValuesStore(); @@ -36,59 +38,102 @@ void initializeStore() { } @Nested - class UsingDefaultNamespaceTests { + class StoringValuesTests { @Test void getWithUnknownKeyReturnsNull() { - assertNull(store.get("unknown key")); + assertNull(store.get(namespace, "unknown key")); } @Test void putAndGetWithSameKey() { - store.put(key, value); - assertEquals(value, store.get(key)); + store.put(namespace, key, value); + assertEquals(value, store.get(namespace, key)); } @Test void valueCanBeReplaced() { - store.put(key, value); + store.put(namespace, key, value); Object newValue = new Object(); - store.put(key, newValue); + store.put(namespace, key, newValue); - assertEquals(newValue, store.get(key)); + assertEquals(newValue, store.get(namespace, key)); } @Test void valueIsComputedIfAbsent() { - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value)); - assertEquals(value, store.get(key)); + assertEquals(value, store.getOrComputeIfAbsent(namespace, key, innerKey -> value)); + assertEquals(value, store.get(namespace, key)); } @Test void valueIsNotComputedIfPresent() { - store.put(key, value); + store.put(namespace, key, value); - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> "a different value")); - assertEquals(value, store.get(key)); + assertEquals(value, store.getOrComputeIfAbsent(namespace, key, innerKey -> "a different value")); + assertEquals(value, store.get(namespace, key)); } @Test void nullIsAValidValueToPut() { - store.put(key, null); + store.put(namespace, key, null); - assertEquals(null, store.getOrComputeIfAbsent(key, innerKey -> "a different value")); - assertEquals(null, store.get(key)); + assertEquals(null, store.getOrComputeIfAbsent(namespace, key, innerKey -> "a different value")); + assertEquals(null, store.get(namespace, key)); } @Test void keysCanBeRemoved() { - store.put(key, value); - store.remove(key); + store.put(namespace, key, value); + assertEquals(value, store.remove(namespace, key)); - assertNull(store.get(key)); - assertEquals("a different value", store.getOrComputeIfAbsent(key, innerKey -> "a different value")); + assertNull(store.get(namespace, key)); + assertEquals("a different value", + store.getOrComputeIfAbsent(namespace, key, innerKey -> "a different value")); + } + + @Test + void sameKeyWithDifferentNamespaces() { + Object value1 = createObject("value1"); + Namespace namespace1 = Namespace.of("ns1"); + + Object value2 = createObject("value2"); + Namespace namespace2 = Namespace.of("ns2"); + + store.put(namespace1, key, value1); + store.put(namespace2, key, value2); + + assertEquals(value1, store.get(namespace1, key)); + assertEquals(value2, store.get(namespace2, key)); + } + + @Test + void valueIsComputedIfAbsentInDifferentNamespace() { + Namespace namespace1 = Namespace.of("ns1"); + Namespace namespace2 = Namespace.of("ns2"); + + assertEquals(value, store.getOrComputeIfAbsent(namespace1, key, innerKey -> value)); + assertEquals(value, store.get(namespace1, key)); + + assertNull(store.get(namespace2, key)); + } + + @Test + void keyIsOnlyRemovedInGivenNamespace() { + Namespace namespace1 = Namespace.of("ns1"); + Namespace namespace2 = Namespace.of("ns2"); + + Object value1 = createObject("value1"); + Object value2 = createObject("value2"); + + store.put(namespace1, key, value1); + store.put(namespace2, key, value2); + store.remove(namespace1, key); + + assertNull(store.get(namespace1, key)); + assertEquals(value2, store.get(namespace2, key)); } } @@ -98,60 +143,52 @@ class InheritedValuesTests { @Test void valueFromParentIsVisible() { - parentStore.put(key, value); - assertEquals(value, store.get(key)); + parentStore.put(namespace, key, value); + assertEquals(value, store.get(namespace, key)); } @Test void valueFromParentCanBeOverriddenInChild() { - parentStore.put(key, value); + parentStore.put(namespace, key, value); Object otherValue = new Object(); - store.put(key, otherValue); - assertEquals(otherValue, store.get(key)); + store.put(namespace, key, otherValue); + assertEquals(otherValue, store.get(namespace, key)); - assertEquals(value, parentStore.get(key)); + assertEquals(value, parentStore.get(namespace, key)); } } @Nested - class UsingExplicitNamespaceTests { + class CompositNamespaceTests { @Test - void sameKeyWithDifferentNamespaces() { - Object value1 = createObject("value1"); - Namespace namespace1 = Namespace.sharedWith("ns1"); + void additionNamespacePartMakesADifferenc() { + + Namespace ns1 = Namespace.of("part1", "part2"); + Namespace ns2 = Namespace.of("part1"); + Namespace ns3 = Namespace.of("part1", "part2"); Object value2 = createObject("value2"); - Namespace namespace2 = Namespace.sharedWith("ns2"); - store.put(key, value1, namespace1); - store.put(key, value2, namespace2); + parentStore.put(ns1, key, value); + parentStore.put(ns2, key, value2); - assertEquals(value1, store.get(key, namespace1)); - assertEquals(value2, store.get(key, namespace2)); + assertEquals(value, store.get(ns1, key)); + assertEquals(value, store.get(ns3, key)); + assertEquals(value2, store.get(ns2, key)); } @Test - void valueIsComputedIfAbsentInDifferentNamespace() { - Namespace namespace = Namespace.sharedWith("ns"); - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value, namespace)); - assertEquals(value, store.get(key, namespace)); + void orderOfNamespacePartsDoesNotMatter() { - assertNull(store.get(key)); - } - - @Test - void keyIsOnlyRemovedInGivenNamespace() { - Namespace namespace = Namespace.sharedWith("ns"); - Object valueInNamespace = createObject("valueInNamespace"); + Namespace ns1 = Namespace.of("part1", "part2"); + Namespace ns2 = Namespace.of("part2", "part1"); - store.put(key, value); - store.put(key, valueInNamespace, namespace); - store.remove(key, namespace); + parentStore.put(ns1, key, value); - assertNull(store.get(key, namespace)); - assertEquals(value, store.get(key)); + assertEquals(value, store.get(ns1, key)); + assertEquals(value, store.get(ns2, key)); } } diff --git a/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java b/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java index 8841dab880a2..5b4220aa8d61 100644 --- a/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java +++ b/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java @@ -11,10 +11,15 @@ package org.junit.gen5.api.extension; import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.HashSet; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Function; +import org.junit.gen5.commons.util.Preconditions; + /** * {@code ExtensionContext} encapsulates the context in which the * current test or container is being executed. @@ -55,82 +60,6 @@ public interface ExtensionContext { AnnotatedElement getElement(); - // Storing methods. - - /** - * Get an object that has been stored using a {@code key} - * - * @param key the key - * @return the value - */ - Object get(Object key); - - /** - * Store a {@code value} for later retrieval using a {@code key}. {@code null} is a valid value. - * - * @param key the key - * @param value the value - */ - void put(Object key, Object value); - - /** - * Get an object that has been stored using a {@code key}. If no value has been store using that {@code key} - * the value will be computed by the {@code defaultCreator} and be stored. - * - * @param key the key - * @param defaultCreator the function called to create the value - * @return the value - */ - Object getOrComputeIfAbsent(Object key, Function defaultCreator); - - /** - * Remove a value that was previously stored using {@code key} so that {@code key} can be used anew. - * - * @param key the key - * @return the previous value or {@code null} if no value was present - * for the specified key - */ - Object remove(Object key); - - /** - * Get an object that has been stored using a {@code key} - * - * @param key the key - * @param namespace the namespace - * @return the value - */ - Object get(Object key, String namespace); - - /** - * Store a {@code value} for later retrieval using a {@code key}. {@code null} is a valid value. - * - * @param key the key - * @param value the value - * @param namespace the namespace - */ - void put(Object key, Object value, String namespace); - - /** - * Get an object that has been stored using a {@code key}. If no value has been store using that {@code key} - * the value will be computed by the {@code defaultCreator} and be stored. - * - * @param key the key - * @param defaultCreator the function called to create the value - * @param namespace the namespace - * @return the value - */ - Object getOrComputeIfAbsent(Object key, Function defaultCreator, String namespace); - - /** - * Remove a value that was previously stored using {@code key} so that {@code key} can be used anew. - * - * @param key the key - * @param namespace the namespace - * @return the previous value or {@code null} if no value was present - * for the specified key and namespace - */ - Object remove(Object key, String namespace); - // Attributes will be removed when storing methods are done Object getAttribute(String key); @@ -139,4 +68,80 @@ public interface ExtensionContext { Object removeAttribute(String key); + default Store getStore() { + return getStore(Namespace.DEFAULT); + } + + Store getStore(Namespace namespace); + + interface Store { + /** + * Get an object that has been stored using a {@code key} + * + * @param key the key + * @return the value + */ + Object get(Object key); + + /** + * Store a {@code value} for later retrieval using a {@code key}. {@code null} is a valid value. + * + * @param key the key + * @param value the value + */ + void put(Object key, Object value); + + /** + * Get an object that has been stored using a {@code key}. If no value has been store using that {@code key} + * the value will be computed by the {@code defaultCreator} and be stored. + * + * @param key the key + * @param defaultCreator the function called to create the value + * @return the value + */ + Object getOrComputeIfAbsent(Object key, Function defaultCreator); + + /** + * Remove a value that was previously stored using {@code key} so that {@code key} can be used anew. + * + * @param key the key + * @return the previous value or {@code null} if no value was present + * for the specified key + */ + Object remove(Object key); + } + + public static class Namespace { + + public static Namespace DEFAULT = Namespace.of(new Object()); + + public static Namespace of(Object... parts) { + Preconditions.notEmpty(Arrays.asList(parts), + "There must be at least one reference object to create a namespace"); + + return new Namespace(parts); + } + + private final Set parts; + + private Namespace(Object... parts) { + this.parts = new HashSet<>(Arrays.asList(parts)); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Namespace namespace = (Namespace) o; + return parts.equals(namespace.parts); + } + + @Override + public int hashCode() { + return parts.hashCode(); + } + } + } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java index 4aef26fcbaaf..bc70a303a24d 100644 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java @@ -13,19 +13,17 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.function.Function; import org.junit.gen5.api.extension.ExtensionContext; import org.junit.gen5.engine.EngineExecutionListener; import org.junit.gen5.engine.TestDescriptor; -import org.junit.gen5.engine.junit5.descriptor.ExtensionValuesStore.Namespace; abstract class AbstractExtensionContext implements ExtensionContext { private final Map attributes = new HashMap<>(); //Will replace attributes if done - private final ExtensionValuesStore store; + private final ExtensionValuesStore valuesStore; private final ExtensionContext parent; private final EngineExecutionListener engineExecutionListener; @@ -36,13 +34,13 @@ abstract class AbstractExtensionContext implements ExtensionContext { this.parent = parent; this.engineExecutionListener = engineExecutionListener; this.testDescriptor = testDescriptor; - this.store = createStore(parent); + this.valuesStore = createStore(parent); } private final ExtensionValuesStore createStore(ExtensionContext parent) { ExtensionValuesStore parentStore = null; if (parent != null) { - parentStore = ((AbstractExtensionContext) parent).store; + parentStore = ((AbstractExtensionContext) parent).valuesStore; } return new ExtensionValuesStore(parentStore); } @@ -79,48 +77,8 @@ protected TestDescriptor getTestDescriptor() { return testDescriptor; } - //Storing methods. All delegate to the store. - //TODO: Remove duplication between these methods and ExtensionValuesStore - // as soon as we have a decision if methods should be exposed on store object instead of via delegation - - @Override - public Object get(Object key) { - return store.get(key); - } - - @Override - public void put(Object key, Object value) { - store.put(key, value); - } - - @Override - public Object getOrComputeIfAbsent(Object key, Function defaultCreator) { - return store.getOrComputeIfAbsent(key, defaultCreator); - } - @Override - public Object remove(Object key) { - return store.remove(key); + public Store getStore(Namespace namespace) { + return new NamespacedStore(valuesStore, namespace); } - - @Override - public Object get(Object key, String namespace) { - return store.get(key, Namespace.sharedWith(namespace)); - } - - @Override - public void put(Object key, Object value, String namespace) { - store.put(key, value, Namespace.sharedWith(namespace)); - } - - @Override - public Object getOrComputeIfAbsent(Object key, Function defaultCreator, String namespace) { - return store.getOrComputeIfAbsent(key, defaultCreator, Namespace.sharedWith(namespace)); - } - - @Override - public Object remove(Object key, String namespace) { - return store.remove(key, Namespace.sharedWith(namespace)); - } - } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java index edc3759c1a7d..b8fd206e0637 100644 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.function.Function; +import org.junit.gen5.api.extension.ExtensionContext.Namespace; import org.junit.gen5.commons.util.Preconditions; /** @@ -33,60 +34,44 @@ public ExtensionValuesStore(ExtensionValuesStore parentStore) { this.parentStore = parentStore; } - public Object get(Object key) { - return get(key, Namespace.DEFAULT); - } - - public Object get(Object key, Namespace namespace) { - StoredValue storedValue = getStoredValue(key, namespace); + public Object get(Namespace namespace, Object key) { + StoredValue storedValue = getStoredValue(namespace, key); if (storedValue != null) return storedValue.value; else if (parentStore != null) - return parentStore.get(key, namespace); + return parentStore.get(namespace, key); else return null; } - private StoredValue getStoredValue(Object key, Namespace namespace) { - ComposedKey composedKey = new ComposedKey(key, namespace); + private StoredValue getStoredValue(Namespace namespace, Object key) { + ComposedKey composedKey = new ComposedKey(namespace, key); return storedValues.get(composedKey); } - public void put(Object key, Object value) { - put(key, value, Namespace.DEFAULT); - } - - public void put(Object key, Object value, Namespace namespace) { + public void put(Namespace namespace, Object key, Object value) { Preconditions.notNull(key, "A key must not be null"); Preconditions.notNull(namespace, "A namespace must not be null"); - putStoredValue(key, namespace, new StoredValue(value)); + putStoredValue(namespace, key, new StoredValue(value)); } - private void putStoredValue(Object key, Namespace namespace, StoredValue storedValue) { - ComposedKey composedKey = new ComposedKey(key, namespace); + private void putStoredValue(Namespace namespace, Object key, StoredValue storedValue) { + ComposedKey composedKey = new ComposedKey(namespace, key); storedValues.put(composedKey, storedValue); } - public Object getOrComputeIfAbsent(Object key, Function defaultCreator) { - return getOrComputeIfAbsent(key, defaultCreator, Namespace.DEFAULT); - } - - public Object getOrComputeIfAbsent(Object key, Function defaultCreator, Namespace namespace) { - StoredValue storedValue = getStoredValue(key, namespace); + public Object getOrComputeIfAbsent(Namespace namespace, Object key, Function defaultCreator) { + StoredValue storedValue = getStoredValue(namespace, key); if (storedValue == null) { storedValue = new StoredValue(defaultCreator.apply(key)); - putStoredValue(key, namespace, storedValue); + putStoredValue(namespace, key, storedValue); } return storedValue.value; } - public Object remove(Object key) { - return remove(key, Namespace.DEFAULT); - } - - public Object remove(Object key, Namespace namespace) { - ComposedKey composedKey = new ComposedKey(key, namespace); + public Object remove(Namespace namespace, Object key) { + ComposedKey composedKey = new ComposedKey(namespace, key); StoredValue previous = storedValues.remove(composedKey); return (previous != null ? previous.value : null); } @@ -96,7 +81,7 @@ private static class ComposedKey { private final Object key; private final Namespace namespace; - private ComposedKey(Object key, Namespace namespace) { + private ComposedKey(Namespace namespace, Object key) { this.key = key; this.namespace = namespace; } @@ -126,36 +111,4 @@ private StoredValue(Object value) { } } - public static class Namespace { - - public static Namespace DEFAULT = Namespace.sharedWith(new Object()); - - public static Namespace sharedWith(Object local) { - Preconditions.notNull(local, "A local must not be null"); - - return new Namespace(local); - } - - private final Object local; - - private Namespace(Object local) { - this.local = local; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - Namespace namespace = (Namespace) o; - return local != null ? local.equals(namespace.local) : namespace.local == null; - } - - @Override - public int hashCode() { - return local != null ? local.hashCode() : 0; - } - } - } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java new file mode 100644 index 000000000000..1a5fa914ebcc --- /dev/null +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2016 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.junit.gen5.engine.junit5.descriptor; + +import java.util.function.Function; + +import org.junit.gen5.api.extension.ExtensionContext.Namespace; +import org.junit.gen5.api.extension.ExtensionContext.Store; + +public class NamespacedStore implements Store { + private final ExtensionValuesStore valuesStore; + private final Namespace namespace; + + public NamespacedStore(ExtensionValuesStore valuesStore, Namespace namespace) { + this.valuesStore = valuesStore; + this.namespace = namespace; + } + + @Override + public Object get(Object key) { + return valuesStore.get(namespace, key); + } + + @Override + public void put(Object key, Object value) { + valuesStore.put(namespace, key, value); + } + + @Override + public Object getOrComputeIfAbsent(Object key, Function defaultCreator) { + return valuesStore.getOrComputeIfAbsent(namespace, key, defaultCreator); + } + + @Override + public Object remove(Object key) { + return valuesStore.remove(namespace, key); + } +} diff --git a/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java b/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java index 3ff10dd6201e..7a79992fbe87 100644 --- a/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java +++ b/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java @@ -49,12 +49,12 @@ public boolean supports(Parameter parameter, MethodInvocationContext methodInvoc @Override public Object resolve(Parameter parameter, MethodInvocationContext methodInvocationContext, ExtensionContext extensionContext) throws ParameterResolutionException { - return getMock(parameter.getType(), extensionContext); + ExtensionContext.Store mocks = extensionContext.getStore(ExtensionContext.Namespace.of(getClass())); + return getMock(parameter.getType(), mocks); } - private Object getMock(Class mockType, ExtensionContext extensionContext) { - return extensionContext.getOrComputeIfAbsent(mockType, type -> mock(mockType), - MockitoExtension.class.getName()); + private Object getMock(Class mockType, ExtensionContext.Store mocks) { + return mocks.getOrComputeIfAbsent(mockType, type -> mock(mockType)); } } diff --git a/sample-extension/src/main/java/com/example/timing/TimingExtension.java b/sample-extension/src/main/java/com/example/timing/TimingExtension.java index 47013f483548..7394c89dace2 100644 --- a/sample-extension/src/main/java/com/example/timing/TimingExtension.java +++ b/sample-extension/src/main/java/com/example/timing/TimingExtension.java @@ -16,6 +16,8 @@ import org.junit.gen5.api.extension.AfterEachExtensionPoint; import org.junit.gen5.api.extension.BeforeEachExtensionPoint; +import org.junit.gen5.api.extension.ExtensionContext; +import org.junit.gen5.api.extension.ExtensionContext.Namespace; import org.junit.gen5.api.extension.ExtensionPointRegistry; import org.junit.gen5.api.extension.ExtensionRegistrar; import org.junit.gen5.api.extension.TestExtensionContext; @@ -35,17 +37,23 @@ public void registerExtensions(ExtensionPointRegistry registry) { private static class TestMethodInvocationWrapper implements BeforeEachExtensionPoint, AfterEachExtensionPoint { - private final String namespace = getClass().getName(); + private final Namespace namespace = Namespace.of(getClass()); @Override public void beforeEach(TestExtensionContext context) throws Exception { - context.put(context.getTestMethod(), System.currentTimeMillis(), namespace); + ExtensionContext.Store times = context.getStore(getNamespace(context)); + times.put(context.getTestMethod(), System.currentTimeMillis()); + } + + private Namespace getNamespace(TestExtensionContext context) { + return Namespace.of(getClass(), context); } @Override public void afterEach(TestExtensionContext context) throws Exception { + ExtensionContext.Store times = context.getStore(getNamespace(context)); Method testMethod = context.getTestMethod(); - long start = (long) context.remove(testMethod, namespace); + long start = (long) times.remove(testMethod); long duration = System.currentTimeMillis() - start; System.out.println(String.format("Method [%s] took %s ms.", testMethod, duration));