You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by rm...@apache.org on 2018/09/04 20:39:42 UTC

svn commit: r1840064 - in /openwebbeans/meecrowave/trunk/meecrowave-junit: ./ src/main/java/org/apache/meecrowave/junit5/ src/test/java/org/apache/meecrowave/junit5/ src/test/java/org/apache/meecrowave/junit5/bean/

Author: rmannibucau
Date: Tue Sep  4 20:39:42 2018
New Revision: 1840064

URL: http://svn.apache.org/viewvc?rev=1840064&view=rev
Log:
MEECROWAVE-141 add @AfterFirstInjection and @AfterLastTest in junit5 integration

Added:
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterFirstInjection.java
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterLastTest.java
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/BaseLifecycle.java
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveTestLifecycleTest.java
      - copied, changed from r1840054, openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveConfigTest.java
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/PerClassMeecrowaveTestLifecycleTest.java
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/bean/
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/bean/Appender.java
Modified:
    openwebbeans/meecrowave/trunk/meecrowave-junit/pom.xml
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MeecrowaveExtension.java
    openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MonoMeecrowaveExtension.java

Modified: openwebbeans/meecrowave/trunk/meecrowave-junit/pom.xml
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/pom.xml?rev=1840064&r1=1840063&r2=1840064&view=diff
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/pom.xml (original)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/pom.xml Tue Sep  4 20:39:42 2018
@@ -62,8 +62,9 @@
     </dependency>
   </dependencies>
 
-  <properties>
-    <junit5.version>5.3.0</junit5.version>
+  <properties> <!-- before upgrading to [5.]3.0 we must upgrade surefire -->
+    <junit5.minor.version>2.0</junit5.minor.version>
+    <junit5.version>5.${junit5.minor.version}</junit5.version>
     <meecrowave.build.name>${project.groupId}.junit</meecrowave.build.name>
   </properties>
 
@@ -76,6 +77,13 @@
           <!-- cause of mono runner/rule -->
           <reuseForks>false</reuseForks>
         </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-engine</artifactId>
+            <version>1.${junit5.minor.version}</version>
+          </dependency>
+        </dependencies>
       </plugin>
     </plugins>
   </build>

Added: openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterFirstInjection.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterFirstInjection.java?rev=1840064&view=auto
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterFirstInjection.java (added)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterFirstInjection.java Tue Sep  4 20:39:42 2018
@@ -0,0 +1,34 @@
+/*
+ * 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.meecrowave.junit5;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Called after the first injection.
+ * This is a kind of @BeforeAll but after injections with test instance (method is not static).
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface AfterFirstInjection {
+}

Added: openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterLastTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterLastTest.java?rev=1840064&view=auto
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterLastTest.java (added)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/AfterLastTest.java Tue Sep  4 20:39:42 2018
@@ -0,0 +1,34 @@
+/*
+ * 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.meecrowave.junit5;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Called after the last test.
+ * This is a kind of @AfterAll but with test instance (method is not static).
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface AfterLastTest {
+}

Added: openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/BaseLifecycle.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/BaseLifecycle.java?rev=1840064&view=auto
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/BaseLifecycle.java (added)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/BaseLifecycle.java Tue Sep  4 20:39:42 2018
@@ -0,0 +1,79 @@
+/*
+ * 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.meecrowave.junit5;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+abstract class BaseLifecycle {
+    boolean isPerClass(final ExtensionContext context) {
+        return context.getTestInstanceLifecycle()
+                .map(it -> it.equals(TestInstance.Lifecycle.PER_CLASS))
+                .orElse(false);
+    }
+
+    LifecyleState onInjection(final ExtensionContext context, final LifecyleState state) {
+        if (state != null && state.injected) {
+            return state;
+        }
+        return context.getTestInstance()
+                .map(test -> invoke(test, AfterFirstInjection.class))
+                .orElse(state);
+    }
+
+    private static LifecyleState invoke(final Object test, final Class<? extends Annotation> marker) {
+        Class<?> type = test.getClass();
+        while (type != Object.class) {
+            Stream.of(type.getDeclaredMethods())
+                    .filter(m -> m.isAnnotationPresent(marker))
+                    .forEach(method -> {
+                        if (!method.isAccessible()) {
+                            method.setAccessible(true);
+                        }
+                        try {
+                            method.invoke(test);
+                        } catch (final IllegalAccessException e) {
+                            throw new IllegalStateException(e);
+                        } catch (final InvocationTargetException ite) {
+                            throw new IllegalStateException(ite.getTargetException());
+                        }
+                    });
+            type = type.getSuperclass();
+        }
+        return new LifecyleState(true, test);
+    }
+
+    static class LifecyleState {
+        private final boolean injected;
+        private final Object instance;
+
+        LifecyleState(final boolean injected, final Object instance) {
+            this.injected = injected;
+            this.instance = instance;
+        }
+
+        void afterLastTest(final ExtensionContext context) {
+            invoke(instance, AfterLastTest.class);
+        }
+    }
+}

Modified: openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MeecrowaveExtension.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MeecrowaveExtension.java?rev=1840064&r1=1840063&r2=1840064&view=diff
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MeecrowaveExtension.java (original)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MeecrowaveExtension.java Tue Sep  4 20:39:42 2018
@@ -19,6 +19,7 @@
 package org.apache.meecrowave.junit5;
 
 import static java.util.Arrays.asList;
+import static java.util.Optional.ofNullable;
 
 import java.io.File;
 import java.lang.annotation.Annotation;
@@ -36,14 +37,14 @@ import org.apache.meecrowave.Meecrowave;
 import org.apache.meecrowave.testing.Injector;
 import org.apache.webbeans.config.WebBeansContext;
 import org.apache.webbeans.spi.ContextsService;
-import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeAllCallback;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
 
-public class MeecrowaveExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback {
+public class MeecrowaveExtension extends BaseLifecycle
+        implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback {
     private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(MeecrowaveExtension.class.getName());
 
     @Override
@@ -87,20 +88,25 @@ public class MeecrowaveExtension impleme
         } else {
             ctx = "";
         }
+        final ExtensionContext.Store store = context.getStore(NAMESPACE);
         final Meecrowave meecrowave = new Meecrowave(builder);
-        context.getStore(NAMESPACE).put(Meecrowave.class.getName(), meecrowave);
-        context.getStore(NAMESPACE).put(Meecrowave.Builder.class.getName(), builder);
+        store.put(Meecrowave.class, meecrowave);
+        store.put(Meecrowave.Builder.class, builder);
         meecrowave.bake(ctx);
 
         if (isPerClass(context)) {
             doInject(context);
+            store.put(LifecyleState.class, onInjection(context, null));
         }
     }
 
     @Override
     public void afterAll(final ExtensionContext context) {
+        final ExtensionContext.Store store = context.getStore(NAMESPACE);
+        ofNullable(store.get(LifecyleState.class, LifecyleState.class))
+                .ifPresent(s -> s.afterLastTest(context));
         if (isPerClass(context)) {
-            Meecrowave.class.cast(context.getStore(NAMESPACE).get(Meecrowave.class.getName())).close();
+            store.get(Meecrowave.class, Meecrowave.class).close();
         }
     }
 
@@ -108,6 +114,8 @@ public class MeecrowaveExtension impleme
     public void beforeEach(final ExtensionContext context) {
         if (!isPerClass(context)) {
             doInject(context);
+            final ExtensionContext.Store store = context.getParent().orElse(context).getStore(NAMESPACE);
+            store.put(LifecyleState.class, onInjection(context, store.get(LifecyleState.class, LifecyleState.class)));
         }
     }
 
@@ -119,7 +127,8 @@ public class MeecrowaveExtension impleme
     }
 
     private void doRelease(final ExtensionContext context) {
-        CreationalContext.class.cast(context.getStore(NAMESPACE).get(CreationalContext.class.getName())).release();
+        ofNullable(context.getStore(NAMESPACE).get(CreationalContext.class, CreationalContext.class))
+                .ifPresent(CreationalContext::release);
         getScopes(context).ifPresent(scopes -> {
             final ContextsService contextsService = WebBeansContext.currentInstance().getContextsService();
             final List<Class<? extends Annotation>> list = new ArrayList<>(asList(scopes));
@@ -128,19 +137,16 @@ public class MeecrowaveExtension impleme
         });
     }
 
-    private Boolean isPerClass(final ExtensionContext context) {
-        return context.getTestInstanceLifecycle()
-                .map(it -> it.equals(TestInstance.Lifecycle.PER_CLASS))
-                .orElse(false);
-    }
-
     private void doInject(final ExtensionContext context) {
         getScopes(context).ifPresent(scopes -> {
             final ContextsService contextsService = WebBeansContext.currentInstance().getContextsService();
             Stream.of(scopes).forEach(s -> contextsService.startContext(s, null));
         });
-        context.getStore(NAMESPACE).put(CreationalContext.class.getName(), Injector.inject(context.getTestInstance().orElse(null)));
-        Injector.injectConfig(Meecrowave.Builder.class.cast(context.getStore(NAMESPACE).get(Meecrowave.Builder.class.getName())), context.getTestInstance().orElse(null));
+        final ExtensionContext.Store store = context.getStore(NAMESPACE);
+        store.put(CreationalContext.class, Injector.inject(context.getTestInstance().orElse(null)));
+        Injector.injectConfig(
+                store.get(Meecrowave.Builder.class, Meecrowave.Builder.class),
+                context.getTestInstance().orElse(null));
     }
 
     private Optional<Class<? extends Annotation>[]> getScopes(final ExtensionContext context) {

Modified: openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MonoMeecrowaveExtension.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MonoMeecrowaveExtension.java?rev=1840064&r1=1840063&r2=1840064&view=diff
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MonoMeecrowaveExtension.java (original)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/main/java/org/apache/meecrowave/junit5/MonoMeecrowaveExtension.java Tue Sep  4 20:39:42 2018
@@ -18,33 +18,41 @@
  */
 package org.apache.meecrowave.junit5;
 
+import static java.util.Optional.ofNullable;
+
 import javax.enterprise.context.spi.CreationalContext;
 
 import org.apache.meecrowave.testing.Injector;
 import org.apache.meecrowave.testing.MonoBase;
-import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeAllCallback;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
 
-public class MonoMeecrowaveExtension implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback, AfterAllCallback {
+public class MonoMeecrowaveExtension extends BaseLifecycle
+        implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback, AfterAllCallback {
     private static final MonoBase BASE = new MonoBase();
     private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(MonoMeecrowaveExtension.class.getName());
 
     @Override
     public void beforeAll(final ExtensionContext context) {
-        context.getStore(NAMESPACE).put(MonoBase.Instance.class.getName(), BASE.startIfNeeded());
+        final ExtensionContext.Store store = context.getStore(NAMESPACE);
+        store.put(MonoBase.Instance.class, BASE.startIfNeeded());
         if (isPerClass(context)) {
             doInject(context);
+            store.put(LifecyleState.class, onInjection(context, null));
         }
     }
 
     @Override
     public void beforeEach(final ExtensionContext context) {
+        final ExtensionContext.Store store = context.getStore(NAMESPACE);
         if (!isPerClass(context)) {
             doInject(context);
+            store.put(
+                LifecyleState.class,
+                onInjection(context.getParent().orElse(context), store.get(LifecyleState.class, LifecyleState.class)));
         }
     }
 
@@ -57,25 +65,22 @@ public class MonoMeecrowaveExtension imp
 
     @Override
     public void afterAll(final ExtensionContext context) {
+        ofNullable(context.getStore(NAMESPACE)
+                .get(LifecyleState.class, LifecyleState.class))
+                .ifPresent(s -> s.afterLastTest(context));
         if (isPerClass(context)) {
             doRelease(context);
         }
     }
 
-    private void doRelease(ExtensionContext context) {
-        CreationalContext.class.cast(context.getStore(NAMESPACE).get(CreationalContext.class.getName())).release();
+    private void doRelease(final ExtensionContext context) {
+        context.getStore(NAMESPACE).get(CreationalContext.class, CreationalContext.class).release();
     }
 
     private void doInject(final ExtensionContext context) {
-        context.getStore(NAMESPACE).put(CreationalContext.class.getName(), Injector.inject(context.getTestInstance().orElse(null)));
+        context.getStore(NAMESPACE).put(CreationalContext.class, Injector.inject(context.getTestInstance().orElse(null)));
         Injector.injectConfig(
-                MonoBase.Instance.class.cast(context.getStore(NAMESPACE).get(MonoBase.Instance.class.getName())).getConfiguration(),
+                context.getStore(NAMESPACE).get(MonoBase.Instance.class, MonoBase.Instance.class).getConfiguration(),
                 context.getTestInstance().orElse(null));
     }
-
-    private Boolean isPerClass(final ExtensionContext context) {
-        return context.getTestInstanceLifecycle()
-                .map(it -> it.equals(TestInstance.Lifecycle.PER_CLASS))
-                .orElse(false);
-    }
 }

Copied: openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveTestLifecycleTest.java (from r1840054, openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveConfigTest.java)
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveTestLifecycleTest.java?p2=openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveTestLifecycleTest.java&p1=openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveConfigTest.java&r1=1840054&r2=1840064&rev=1840064&view=diff
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveConfigTest.java (original)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/MeecrowaveTestLifecycleTest.java Tue Sep  4 20:39:42 2018
@@ -18,35 +18,64 @@
  */
 package org.apache.meecrowave.junit5;
 
-import org.apache.meecrowave.Meecrowave;
-import org.apache.meecrowave.io.IO;
-import org.apache.meecrowave.testing.ConfigurationInject;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import javax.inject.Inject;
+
+import org.apache.meecrowave.junit5.bean.Appender;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
+@MeecrowaveConfig(scanningPackageIncludes = "org.apache.meecrowave.junit5.bean")
+class MeecrowaveTestLifecycleTest {
+    private static Appender global;
+
+    @Inject
+    private Appender appender;
+
+    private MeecrowaveTestLifecycleTest firstInjectionInstance;
+
+    @AfterFirstInjection
+    void afterInjection() {
+        appender.reset();
+        global = appender;
+        appender.append("afterInjection");
+        firstInjectionInstance = this;
+    }
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+    @BeforeEach
+    void beforeEach() {
+        appender.append("beforeEach");
+    }
 
-@MeecrowaveConfig
-class MeecrowaveConfigTest {
-    @ConfigurationInject
-    private Meecrowave.Builder config;
+    @Test
+    void test1() {
+        assertTrue(appender.get().startsWith("afterInjection/beforeEach"));
+        appender.append("test");
+    }
 
     @Test
-    void run() throws MalformedURLException {
-        assertEquals("simple", slurp(new URL("http://localhost:" + config.getHttpPort() + "/api/test")));
+    void test2() {
+        test1(); // exact same impl but here to ensure we call afterInjection only once for N methods
+    }
+
+    @AfterEach
+    void afterEach() {
+        appender.append("afterEach");
+    }
+
+    @AfterLastTest
+    void afterLast() {
+        appender.append("afterLast");
+        assertEquals(firstInjectionInstance, this);
     }
 
-    private String slurp(final URL url) {
-        try (final InputStream is = url.openStream()) {
-            return IO.toString(is);
-        } catch (final IOException e) {
-            fail(e.getMessage());
-        }
-        return null;
+    @AfterAll
+    static void afterAll() {
+        assertEquals("afterInjection/beforeEach/test/afterEach/beforeEach/test/afterEach", global.get());
     }
 }

Added: openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/PerClassMeecrowaveTestLifecycleTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/PerClassMeecrowaveTestLifecycleTest.java?rev=1840064&view=auto
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/PerClassMeecrowaveTestLifecycleTest.java (added)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/PerClassMeecrowaveTestLifecycleTest.java Tue Sep  4 20:39:42 2018
@@ -0,0 +1,77 @@
+/*
+ * 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.meecrowave.junit5;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
+
+import javax.inject.Inject;
+
+import org.apache.meecrowave.junit5.bean.Appender;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+@TestInstance(PER_CLASS)
+@MeecrowaveConfig(scanningPackageIncludes = "org.apache.meecrowave.junit5.bean")
+class PerClassMeecrowaveTestLifecycleTest {
+    private static Appender global;
+
+    @Inject
+    private Appender appender;
+
+    private PerClassMeecrowaveTestLifecycleTest firstInjectionInstance;
+
+    @AfterFirstInjection
+    void afterInjection() {
+        appender.reset();
+        global = appender;
+        appender.append("afterInjection");
+        firstInjectionInstance = this;
+    }
+
+    @BeforeEach
+    void beforeEach() {
+        appender.append("beforeEach");
+    }
+
+    @Test
+    void test() {
+        assertEquals("afterInjection/beforeEach", appender.get());
+        appender.append("test");
+    }
+
+    @AfterEach
+    void afterEach() {
+        appender.append("afterEach");
+    }
+
+    @AfterLastTest
+    void afterLast() {
+        appender.append("afterLast");
+        assertEquals(firstInjectionInstance, this);
+    }
+
+    @AfterAll
+    static void afterAll() {
+        assertEquals("afterInjection/beforeEach/test/afterEach", global.get());
+    }
+}

Added: openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/bean/Appender.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/bean/Appender.java?rev=1840064&view=auto
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/bean/Appender.java (added)
+++ openwebbeans/meecrowave/trunk/meecrowave-junit/src/test/java/org/apache/meecrowave/junit5/bean/Appender.java Tue Sep  4 20:39:42 2018
@@ -0,0 +1,38 @@
+/*
+ * 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.meecrowave.junit5.bean;
+
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class Appender {
+    private String value;
+
+    public void append(final String value) {
+        this.value = (this.value != null ? this.value + '/' : "") + value;
+    }
+
+    public String get() {
+        return value;
+    }
+
+    public void reset() {
+        value = null;
+    }
+}