From b5b7f157bacc90bc61b4b6e5a6d849454c79569f Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 21 Nov 2024 12:37:59 +0100 Subject: [PATCH] testing-Tools DebuggerDetection and @IgnoreOnFailure with IgnoreOnFailureExtension --- .../hsadminng/test/DebuggerDetection.java | 14 +++++ .../hsadminng/test/IgnoreOnFailure.java | 20 +++++++ .../test/IgnoreOnFailureExtension.java | 52 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 src/test/java/net/hostsharing/hsadminng/test/DebuggerDetection.java create mode 100644 src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailure.java create mode 100644 src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailureExtension.java diff --git a/src/test/java/net/hostsharing/hsadminng/test/DebuggerDetection.java b/src/test/java/net/hostsharing/hsadminng/test/DebuggerDetection.java new file mode 100644 index 00000000..49fcaec6 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/test/DebuggerDetection.java @@ -0,0 +1,14 @@ +package net.hostsharing.hsadminng.test; + +import lombok.experimental.UtilityClass; + +import java.lang.management.ManagementFactory; + +@UtilityClass +public class DebuggerDetection { + public static boolean isDebuggerAttached() { + // check for typical debug arguments in the JVM input arguments + return ManagementFactory.getRuntimeMXBean().getInputArguments().stream() + .anyMatch(arg -> arg.contains("-agentlib:jdwp")); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailure.java b/src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailure.java new file mode 100644 index 00000000..6a2a885d --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailure.java @@ -0,0 +1,20 @@ +package net.hostsharing.hsadminng.test; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Use this annotation on JUnit Jupiter test-methods to convert failure to ignore. + * + *

+ * The test-class also has to add the extension {link IgnoreOnFailureExtension}. + *

+ */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface IgnoreOnFailure { + /// a comment, e.g. about the feature under construction + String value() default ""; +} diff --git a/src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailureExtension.java b/src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailureExtension.java new file mode 100644 index 00000000..511b89fd --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/test/IgnoreOnFailureExtension.java @@ -0,0 +1,52 @@ +package net.hostsharing.hsadminng.test; + +import org.junit.jupiter.api.extension.ExtensionContext; + +import org.junit.jupiter.api.extension.InvocationInterceptor; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; + +import java.lang.reflect.Method; + +import static org.assertj.core.api.Assumptions.assumeThat; + +/** + * Use this JUnit Jupiter extension to ignore failing tests annotated with annotation {@link IgnoreOnFailure}. + * + *

+ * This is useful for outside-in-TDD, if you write a high-level (e.g. Acceptance- or Scenario-Test) before + * you even have an implementation for that new feature. + * As long as no other tests breaks, it's not a real problem merging your new test and incomplete implementation. + *

+ *

+ * Once the test turns green, remove the annotation {@link IgnoreOnFailure}. + *

+ * + */ +// BLOG: A JUnit Jupiter extension to ignore failed acceptance tests for outside-in TDD +public class IgnoreOnFailureExtension implements InvocationInterceptor { + + /// @hidden + @Override + public void interceptTestMethod( + final Invocation invocation, + final ReflectiveInvocationContext invocationContext, + final ExtensionContext extensionContext) throws Throwable { + + try { + invocation.proceed(); + } catch (final Throwable throwable) { + if (hasIgnoreOnFailureAnnotation(extensionContext)) { + assumeThat(true).as("ignoring failed test with @" + IgnoreOnFailure.class.getSimpleName()).isFalse(); + } else { + throw throwable; + } + } + } + + private static boolean hasIgnoreOnFailureAnnotation(final ExtensionContext context) { + final var hasIgnoreOnFailureAnnotation = context.getTestMethod() + .map(method -> method.getAnnotation(IgnoreOnFailure.class)) + .isPresent(); + return hasIgnoreOnFailureAnnotation; + } +}