SLING-7803 add junit5 extension
diff --git a/junit4/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextBuilder.java b/junit4/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextBuilder.java
index 81bd569..cdd293e 100644
--- a/junit4/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextBuilder.java
+++ b/junit4/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextBuilder.java
@@ -34,7 +34,7 @@
     private final @NotNull ContextPlugins plugins = new ContextPlugins();
     
     /**
-     * Create builder with default resource resolver type.
+     * Create builder.
      */
     public OsgiContextBuilder() {}
     
diff --git a/junit5/pom.xml b/junit5/pom.xml
index ba9c30b..c6989ad 100644
--- a/junit5/pom.xml
+++ b/junit5/pom.xml
@@ -59,7 +59,43 @@
             <scope>test</scope>
         </dependency>
 
+        <!-- JUnit 5 -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.vintage</groupId>
+            <artifactId>junit-vintage-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
+    
+    <dependencyManagement>
+        <dependencies>
+      
+            <dependency>
+                <groupId>org.junit</groupId>
+                <artifactId>junit-bom</artifactId>
+                <version>5.2.0</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+      
+        </dependencies>
+    </dependencyManagement>
 
     <build>
         <plugins>
diff --git a/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContext.java b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContext.java
new file mode 100644
index 0000000..f57ddaa
--- /dev/null
+++ b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContext.java
@@ -0,0 +1,78 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import org.apache.sling.testing.mock.osgi.context.ContextPlugins;
+import org.apache.sling.testing.mock.osgi.context.OsgiContextImpl;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * OSGi Mock parameter object.
+ * <p>
+ * Additionally you can subclass this class and provide further parameters via
+ * {@link OsgiContextBuilder}.
+ * </p>
+ */
+@ConsumerType
+public final class OsgiContext extends OsgiContextImpl {
+
+    private final ContextPlugins plugins;
+    private boolean isSetUp;
+
+    /**
+     * Initialize OSGi context.
+     */
+    public OsgiContext() {
+        this(new ContextPlugins());
+    }
+
+    /**
+     * Initialize OSGi context.
+     * @param contextPlugins Context plugins
+     */
+    OsgiContext(@NotNull final ContextPlugins contextPlugins) {
+        this.plugins = contextPlugins;
+    }
+
+    /**
+     * This is called by {@link OsgiContextExtension} to set up context.
+     */
+    protected void setUpContext() {
+        isSetUp = true;
+        plugins.executeBeforeSetUpCallback(this);
+        super.setUp();
+    }
+
+    /**
+     * This is called by {@link OsgiContextExtension} to tear down context.
+     */
+    protected void tearDownContext() {
+        super.tearDown();
+    }
+
+    ContextPlugins getContextPlugins() {
+        return plugins;
+    }
+
+    boolean isSetUp() {
+        return this.isSetUp;
+    }
+
+}
diff --git a/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextBuilder.java b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextBuilder.java
new file mode 100644
index 0000000..8a90f81
--- /dev/null
+++ b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextBuilder.java
@@ -0,0 +1,112 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import org.apache.sling.testing.mock.osgi.context.ContextCallback;
+import org.apache.sling.testing.mock.osgi.context.ContextPlugin;
+import org.apache.sling.testing.mock.osgi.context.ContextPlugins;
+import org.apache.sling.testing.mock.osgi.context.OsgiContextImpl;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Builder class for creating {@link OsgiContext} instances with different sets
+ * of parameters.
+ */
+@ProviderType
+public final class OsgiContextBuilder {
+
+    private final @NotNull ContextPlugins plugins = new ContextPlugins();
+
+    /**
+     * Create builder.
+     */
+    public OsgiContextBuilder() {}
+
+    /**
+     * @param <T> context type
+     * @param plugin Context plugin which listens to context lifecycle events.
+     * @return this
+     */
+    @SafeVarargs
+    public final <T extends OsgiContextImpl> OsgiContextBuilder plugin(@NotNull ContextPlugin<T> @NotNull ... plugin) {
+        plugins.addPlugin(plugin);
+        return this;
+    }
+
+    /**
+     * @param <T> context type
+     * @param beforeSetUpCallback Allows the application to register an own
+     *            callback function that is called before the built-in setup
+     *            rules are executed.
+     * @return this
+     */
+    @SafeVarargs
+    public final <T extends OsgiContextImpl> OsgiContextBuilder beforeSetUp(@NotNull ContextCallback<T> @NotNull ... beforeSetUpCallback) {
+        plugins.addBeforeSetUpCallback(beforeSetUpCallback);
+        return this;
+    }
+
+    /**
+     * @param <T> context type
+     * @param afterSetUpCallback Allows the application to register an own
+     *            callback function that is called after the built-in setup
+     *            rules are executed.
+     * @return this
+     */
+    @SafeVarargs
+    public final <T extends OsgiContextImpl> OsgiContextBuilder afterSetUp(@NotNull ContextCallback<T> @NotNull ... afterSetUpCallback) {
+        plugins.addAfterSetUpCallback(afterSetUpCallback);
+        return this;
+    }
+
+    /**
+     * @param <T> context type
+     * @param beforeTearDownCallback Allows the application to register an own
+     *            callback function that is called before the built-in teardown
+     *            rules are executed.
+     * @return this
+     */
+    @SafeVarargs
+    public final <T extends OsgiContextImpl> OsgiContextBuilder beforeTearDown(@NotNull ContextCallback<T> @NotNull ... beforeTearDownCallback) {
+        plugins.addBeforeTearDownCallback(beforeTearDownCallback);
+        return this;
+    }
+
+    /**
+     * @param <T> context type
+     * @param afterTearDownCallback Allows the application to register an own
+     *            callback function that is after before the built-in teardown
+     *            rules are executed.
+     * @return this
+     */
+    @SafeVarargs
+    public final <T extends OsgiContextImpl> OsgiContextBuilder afterTearDown(@NotNull ContextCallback<T> @NotNull ... afterTearDownCallback) {
+        plugins.addAfterTearDownCallback(afterTearDownCallback);
+        return this;
+    }
+
+    /**
+     * @return Build {@link OsgiContext} instance.
+     */
+    public @NotNull OsgiContext build() {
+        return new OsgiContext(this.plugins);
+    }
+
+}
diff --git a/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextCallback.java b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextCallback.java
new file mode 100644
index 0000000..afe42a9
--- /dev/null
+++ b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextCallback.java
@@ -0,0 +1,33 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import org.apache.sling.testing.mock.osgi.context.ContextCallback;
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Callback interface for application-specific setup and teardown operations to
+ * customize the {@link OsgiContext} JUnit parameter context.
+ */
+@ConsumerType
+public interface OsgiContextCallback extends ContextCallback<OsgiContext> {
+
+    // specialized version of ContextCallback
+
+}
diff --git a/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextExtension.java b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextExtension.java
new file mode 100644
index 0000000..608238f
--- /dev/null
+++ b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextExtension.java
@@ -0,0 +1,125 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.junit.jupiter.api.extension.TestInstancePostProcessor;
+
+/**
+ * JUnit 5 extension that allows to inject {@link OsgiContext} (or subclasses of
+ * it) parameters in test methods, and ensures that the context is set up and
+ * teared down properly for each test method.
+ */
+public final class OsgiContextExtension implements ParameterResolver, TestInstancePostProcessor, BeforeEachCallback,
+        AfterEachCallback, AfterTestExecutionCallback {
+
+    /**
+     * Checks if test class has a {@link OsgiContext} or derived field. If it has
+     * and is not instantiated, create an new {@link OsgiContext} and store it in
+     * the field. If it is already instantiated reuse this instance and use it
+     * for all test methods.
+     */
+    @Override
+    public void postProcessTestInstance(Object testInstance, ExtensionContext extensionContext) throws Exception {
+        Field osgiContextField = getFieldFromTestInstance(testInstance, OsgiContext.class);
+        if (osgiContextField != null) {
+            OsgiContext context = (OsgiContext)osgiContextField.get(testInstance);
+            if (context != null) {
+                if (!context.isSetUp()) {
+                    context.setUpContext();
+                }
+                OsgiContextStore.storeOsgiContext(extensionContext, testInstance, context);
+            } else {
+                context = OsgiContextStore.getOrCreateOsgiContext(extensionContext, testInstance);
+                osgiContextField.set(testInstance, context);
+            }
+        }
+    }
+
+    /**
+     * Support parameter injection for test methods of parameter type is derived from {@link OsgiContext}.
+     */
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
+        return OsgiContext.class.isAssignableFrom(parameterContext.getParameter().getType());
+    }
+
+    /**
+     * Resolve (or create) {@link OsgiContext} instance for test method parameter.
+     */
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
+        return OsgiContextStore.getOrCreateOsgiContext(extensionContext, extensionContext.getRequiredTestInstance());
+    }
+
+    @Override
+    public void beforeEach(ExtensionContext extensionContext) throws Exception {
+        applyOsgiContext(extensionContext, osgiContext -> {
+            // call context plugins setup after all @BeforeEach methods were called
+            osgiContext.getContextPlugins().executeAfterSetUpCallback(osgiContext);
+        });
+    }
+
+    @Override
+    public void afterTestExecution(ExtensionContext extensionContext) throws Exception {
+        applyOsgiContext(extensionContext, osgiContext -> {
+            // call context plugins setup before any @AfterEach method is called
+            osgiContext.getContextPlugins().executeBeforeTearDownCallback(osgiContext);
+        });
+    }
+
+    @Override
+    public void afterEach(ExtensionContext extensionContext) {
+        applyOsgiContext(extensionContext, osgiContext -> {
+            // call context plugins setup after all @AfterEach methods were called
+            osgiContext.getContextPlugins().executeAfterTearDownCallback(osgiContext);
+
+            // Tear down {@link OsgiContext} after test is complete.
+            osgiContext.tearDownContext();
+            OsgiContextStore.removeOsgiContext(extensionContext, extensionContext.getRequiredTestInstance());
+        });
+    }
+
+    private void applyOsgiContext(ExtensionContext extensionContext, Consumer<OsgiContext> consumer) {
+        OsgiContext osgiContext = OsgiContextStore.getOsgiContext(extensionContext,
+                extensionContext.getRequiredTestInstance());
+        if (osgiContext != null) {
+            consumer.accept(osgiContext);
+        }
+    }
+
+    private Field getFieldFromTestInstance(Object testInstance, Class<?> type) {
+        Field contextField = Arrays.stream(testInstance.getClass().getDeclaredFields())
+                .filter(field -> type.isAssignableFrom(field.getType())).findFirst().orElse(null);
+        if (contextField != null) {
+            contextField.setAccessible(true);
+        }
+        return contextField;
+    }
+
+}
diff --git a/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextStore.java b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextStore.java
new file mode 100644
index 0000000..f7f31d3
--- /dev/null
+++ b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextStore.java
@@ -0,0 +1,92 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
+import org.junit.jupiter.api.extension.ExtensionContext.Store;
+
+/**
+ * Helper class managing storage of {@link OsgiContext} in extension context
+ * store.
+ */
+final class OsgiContextStore {
+
+    private static final Namespace OSGi_CONTEXT_NAMESPACE = Namespace.create(OsgiContextExtension.class);
+
+    private OsgiContextStore() {
+        // static methods only
+    }
+
+    /**
+     * Get {@link OsgiContext} from extension context store.
+     * @param extensionContext Extension context
+     * @param testInstance Test instance
+     * @return OsgiContext or null
+     */
+    public static OsgiContext getOsgiContext(ExtensionContext extensionContext, Object testInstance) {
+        return getStore(extensionContext).get(testInstance, OsgiContext.class);
+    }
+
+    /**
+     * Get {@link OsgiContext} from extension context store - if it does not
+     * exist create a new one and store it.
+     * @param extensionContext Extension context
+     * @param testInstance Test instance
+     * @return OsgiContext (never null)
+     */
+    public static OsgiContext getOrCreateOsgiContext(ExtensionContext extensionContext, Object testInstance) {
+        OsgiContext context = getOsgiContext(extensionContext, testInstance);
+        if (context == null) {
+            context = createOsgiContext(extensionContext);
+            storeOsgiContext(extensionContext, testInstance, context);
+        }
+        return context;
+    }
+
+    /**
+     * Removes {@link OsgiContext} from extension context store (if it exists).
+     * @param extensionContext Extension context
+     * @param testInstance Test instance
+     */
+    public static void removeOsgiContext(ExtensionContext extensionContext, Object testInstance) {
+        getStore(extensionContext).remove(testInstance);
+    }
+
+    /**
+     * Store {@link OsgiContext} in extension context store.
+     * @param extensionContext Extension context
+     * @param testInstance Test instance
+     * @param osgiContext OSGi context
+     */
+    public static void storeOsgiContext(ExtensionContext extensionContext, Object testInstance, OsgiContext osgiContext) {
+        getStore(extensionContext).put(testInstance, osgiContext);
+    }
+
+    private static Store getStore(ExtensionContext context) {
+        return context.getStore(OSGi_CONTEXT_NAMESPACE);
+    }
+
+    private static OsgiContext createOsgiContext(ExtensionContext extensionContext) {
+        OsgiContext osgiContext = new OsgiContext();
+        osgiContext.setUpContext();
+        return osgiContext;
+    }
+
+}
diff --git a/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/package-info.java b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/package-info.java
new file mode 100644
index 0000000..7cb00c7
--- /dev/null
+++ b/junit5/src/main/java/org/apache/sling/testing/mock/osgi/junit5/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * JUnit 5 extensions for OSGi context.
+ */
+@org.osgi.annotation.versioning.Version("1.0.0")
+package org.apache.sling.testing.mock.osgi.junit5;
diff --git a/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextMemberInstantiatedTest.java b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextMemberInstantiatedTest.java
new file mode 100644
index 0000000..07a98b2
--- /dev/null
+++ b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextMemberInstantiatedTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * Test with {@link OsgiContext} as class member variable already instantiated.
+ */
+@ExtendWith(OsgiContextExtension.class)
+class OsgiContextMemberInstantiatedTest {
+
+    OsgiContext context = new OsgiContext();
+
+    @Test
+    void testSimpleService() {
+        context.registerInjectActivateService(new Integer(5));
+        
+        Integer service = context.getService(Integer.class);
+        assertEquals((Integer)5, service);
+    }
+
+}
diff --git a/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextMemberTest.java b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextMemberTest.java
new file mode 100644
index 0000000..e1cf9c1
--- /dev/null
+++ b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextMemberTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * Test with {@link OsgiContext} as class member variable.
+ */
+@ExtendWith(OsgiContextExtension.class)
+class OsgiContextMemberTest {
+
+    OsgiContext context;
+
+    @Test
+    void testSimpleService() {
+        context.registerInjectActivateService(new Integer(5));
+        
+        Integer service = context.getService(Integer.class);
+        assertEquals((Integer)5, service);
+    }
+
+}
diff --git a/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextPluginTest.java b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextPluginTest.java
new file mode 100644
index 0000000..111d6d6
--- /dev/null
+++ b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextPluginTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * Test with {@link OsgiContext} with context plugins.
+ */
+@ExtendWith(OsgiContextExtension.class)
+class OsgiContextPluginTest {
+
+    private final @NotNull OsgiContextCallback contextBeforeSetup = mock(OsgiContextCallback.class);
+    private final @NotNull OsgiContextCallback contextAfterSetup = mock(OsgiContextCallback.class);
+    private final @NotNull OsgiContextCallback contextBeforeTeardown = mock(OsgiContextCallback.class);
+    private final @NotNull OsgiContextCallback contextAfterTeardown = mock(OsgiContextCallback.class);
+
+    private final @NotNull OsgiContext context = new OsgiContextBuilder()
+            .beforeSetUp(contextBeforeSetup)
+            .afterSetUp(contextAfterSetup)
+            .beforeTearDown(contextBeforeTeardown)
+            .afterTearDown(contextAfterTeardown)
+            .build();
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        verify(contextBeforeSetup).execute(context);
+    }
+
+    @Test
+    public void testRequest() throws Exception {
+        verify(contextAfterSetup).execute(context);
+    }
+
+    @Test
+    public void testResourceResolverFactoryActivatorProps() throws Exception {
+        verify(contextAfterSetup).execute(context);
+    }
+
+    @AfterEach
+    public void tearDown() throws Exception {
+        verify(contextBeforeTeardown).execute(context);
+    }
+
+}
diff --git a/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextTest.java b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextTest.java
new file mode 100644
index 0000000..40785f5
--- /dev/null
+++ b/junit5/src/test/java/org/apache/sling/testing/mock/osgi/junit5/OsgiContextTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.apache.sling.testing.mock.osgi.junit5;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ * Test with {@link OsgiContext} as test method parameter.
+ */
+@ExtendWith(OsgiContextExtension.class)
+class OsgiContextTest {
+
+    @Test
+    void testSimpleService(OsgiContext context) {
+        context.registerInjectActivateService(new Integer(5));
+        
+        Integer service = context.getService(Integer.class);
+        assertEquals((Integer)5, service);
+    }
+
+}