Skip to content

Commit

Permalink
Use meta-annotated Scenario annotation to activate fail-fast executio…
Browse files Browse the repository at this point in the history
…n mode
  • Loading branch information
sormuras committed May 4, 2017
1 parent 18cc080 commit 9b1f57b
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 8 deletions.
3 changes: 2 additions & 1 deletion documentation/src/test/java/example/DynamicTestsDemo.java
Expand Up @@ -29,6 +29,7 @@

import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Scenario;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.ThrowingConsumer;
Expand All @@ -44,7 +45,7 @@ List<String> dynamicTestsWithInvalidReturnType() {
return Arrays.asList("Hello");
}

@TestFactory
@Scenario
Stream<DynamicNode> scenarioTests() {
// end::user_guide[]
// @formatter:off
Expand Down
@@ -0,0 +1,37 @@
/*
* Copyright 2015-2017 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.jupiter.api;

import static org.junit.platform.commons.meta.API.Usage.Experimental;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.junit.platform.commons.meta.API;

/**
* {@code @Scenario} is used to signal that the annotated method is a
* <em>test factory</em> method with fail-fast execution mode.
*
* @since 5.0
* @see TestFactory
* @see DynamicTest
*/
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(Experimental)
@TestFactory
public @interface Scenario {
}
Expand Up @@ -29,11 +29,14 @@ class DynamicContainerTestDescriptor extends JupiterTestDescriptor {

private final DynamicContainer dynamicContainer;
private final TestSource testSource;
private final boolean breakOnFailure;

DynamicContainerTestDescriptor(UniqueId uniqueId, DynamicContainer dynamicContainer, TestSource testSource) {
DynamicContainerTestDescriptor(UniqueId uniqueId, DynamicContainer dynamicContainer, TestSource testSource,
boolean breakOnFailure) {
super(uniqueId, dynamicContainer.getDisplayName());
this.dynamicContainer = dynamicContainer;
this.testSource = testSource;
this.breakOnFailure = breakOnFailure;
setSource(testSource);
}

Expand All @@ -47,9 +50,12 @@ public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext conte
DynamicTestExecutor dynamicTestExecutor) throws Exception {
int index = 1;
for (DynamicNode childNode : dynamicContainer.getDynamicNodes()) {
JupiterTestDescriptor childDescriptor = createDynamicDescriptor(this, childNode, index++, testSource);
JupiterTestDescriptor childDescriptor = createDynamicDescriptor(this, childNode, index++, testSource,
breakOnFailure);
if (!isTestResultPresentAndSuccessful(dynamicTestExecutor.execute(childDescriptor))) {
break;
if (breakOnFailure) {
break;
}
}
}
return context;
Expand Down
Expand Up @@ -20,11 +20,13 @@
import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Scenario;
import org.junit.jupiter.api.extension.TestExtensionContext;
import org.junit.jupiter.engine.execution.ExecutableInvoker;
import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext;
import org.junit.platform.commons.JUnitException;
import org.junit.platform.commons.meta.API;
import org.junit.platform.commons.util.AnnotationUtils;
import org.junit.platform.commons.util.CollectionUtils;
import org.junit.platform.commons.util.PreconditionViolationException;
import org.junit.platform.engine.TestExecutionResult;
Expand All @@ -45,8 +47,11 @@ public class TestFactoryTestDescriptor extends MethodTestDescriptor {

private static final ExecutableInvoker executableInvoker = new ExecutableInvoker();

private final boolean breakOnFailure;

public TestFactoryTestDescriptor(UniqueId uniqueId, Class<?> testClass, Method testMethod) {
super(uniqueId, testClass, testMethod);
this.breakOnFailure = AnnotationUtils.findAnnotation(testMethod, Scenario.class).isPresent();
}

// --- TestDescriptor ------------------------------------------------------
Expand Down Expand Up @@ -77,9 +82,12 @@ protected void invokeTestMethod(JupiterEngineExecutionContext context, DynamicTe
Iterator<DynamicNode> iterator = dynamicNodeStream.iterator();
while (iterator.hasNext()) {
DynamicNode dynamicNode = iterator.next();
JupiterTestDescriptor descriptor = createDynamicDescriptor(this, dynamicNode, index++, source);
JupiterTestDescriptor descriptor = createDynamicDescriptor(this, dynamicNode, index++, source,
breakOnFailure);
if (!isTestResultPresentAndSuccessful(dynamicTestExecutor.execute(descriptor))) {
break;
if (breakOnFailure) {
break;
}
}
}
}
Expand All @@ -104,7 +112,7 @@ static boolean isTestResultPresentAndSuccessful(Optional<TestExecutionResult> re
}

static JupiterTestDescriptor createDynamicDescriptor(JupiterTestDescriptor parent, DynamicNode node, int index,
TestSource source) {
TestSource source, boolean breakOnFailure) {
JupiterTestDescriptor descriptor;
if (node instanceof DynamicTest) {
DynamicTest test = (DynamicTest) node;
Expand All @@ -114,7 +122,7 @@ static JupiterTestDescriptor createDynamicDescriptor(JupiterTestDescriptor paren
else {
DynamicContainer container = (DynamicContainer) node;
UniqueId uniqueId = parent.getUniqueId().append(DYNAMIC_CONTAINER_SEGMENT_TYPE, "#" + index);
descriptor = new DynamicContainerTestDescriptor(uniqueId, container, source);
descriptor = new DynamicContainerTestDescriptor(uniqueId, container, source, breakOnFailure);
}
parent.addChild(descriptor);
return descriptor;
Expand Down

0 comments on commit 9b1f57b

Please sign in to comment.