Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8512b10

Browse files
committed
[JUnit] Use AssumptionFailed to mark scenarios/steps as skipped
Since it is only after a step or scenario has been executed we can tell if it should be considered skipped in JUnit terms, TestAssumptionFailed notifications suits better than TestIgnored notifications. By using TestAssumptionFailed to mark scenarios/steps as skipped, TestStarted can always be fired before the scenario/step is executed, therefore the option --allow-stared-ignored is not longer needed.
1 parent aa069b0 commit 8512b10

File tree

9 files changed

+497
-275
lines changed

9 files changed

+497
-275
lines changed

junit/src/main/java/cucumber/runtime/junit/JUnitOptions.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ public class JUnitOptions {
1212
private static final String OPTIONS_RESOURCE = "/cucumber/api/junit/OPTIONS.txt";
1313
private static String optionsText;
1414

15-
private boolean allowStartedIgnored = false;
1615
private boolean filenameCompatibleNames = false;
1716
private boolean stepNotifications = true;
1817

@@ -36,7 +35,9 @@ private void parse(List<String> args) {
3635
printOptions();
3736
System.exit(0);
3837
} else if (arg.equals("--no-allow-started-ignored") || arg.equals("--allow-started-ignored")) {
39-
allowStartedIgnored = !arg.startsWith("--no-");
38+
System.err.println("WARNING: Found tags option '" + arg + "'. " +
39+
"--allow-started-ignored has no effect, testStarted is always fired before a test is started." +
40+
"--allow-started-ignored will be removed from the next release of Cucumber-JVM");
4041
} else if (arg.equals("--no-filename-compatible-names") || arg.equals("--filename-compatible-names")) {
4142
filenameCompatibleNames = !arg.startsWith("--no-");
4243
} else if (arg.equals("--no-step-notifications") || arg.equals("--step-notifications")) {
@@ -47,9 +48,6 @@ private void parse(List<String> args) {
4748
}
4849
}
4950

50-
boolean allowStartedIgnored() {
51-
return allowStartedIgnored;
52-
}
5351
boolean filenameCompatibleNames() {
5452
return filenameCompatibleNames;
5553
}
Lines changed: 89 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package cucumber.runtime.junit;
22

3-
import cucumber.api.PendingException;
43
import cucumber.api.Result;
4+
import cucumber.api.TestStep;
55
import cucumber.api.event.EventHandler;
6+
import cucumber.api.event.TestCaseFinished;
7+
import cucumber.api.event.TestCaseStarted;
68
import cucumber.api.event.TestStepFinished;
79
import cucumber.api.event.TestStepStarted;
810
import cucumber.runner.EventBus;
@@ -13,7 +15,7 @@
1315
import org.junit.runner.notification.RunNotifier;
1416
import org.junit.runners.model.MultipleFailureException;
1517

16-
import static cucumber.runtime.Runtime.isPending;
18+
import java.util.ArrayList;
1719

1820
public class JUnitReporter {
1921

@@ -24,8 +26,15 @@ public class JUnitReporter {
2426
private PickleRunner pickleRunner;
2527
private RunNotifier runNotifier;
2628
TestNotifier pickleRunnerNotifier; // package-private for testing
27-
private boolean failedStep;
28-
private boolean ignoredStep;
29+
ArrayList<Throwable> stepErrors; // package-private for testing
30+
private final EventHandler<TestCaseStarted> testCaseStartedHandler = new EventHandler<TestCaseStarted>() {
31+
32+
@Override
33+
public void receive(TestCaseStarted event) {
34+
handleTestCaseStarted();
35+
}
36+
37+
};
2938
private final EventHandler<TestStepStarted> testStepStartedHandler = new EventHandler<TestStepStarted>() {
3039

3140
@Override
@@ -40,38 +49,43 @@ public void receive(TestStepStarted event) {
4049

4150
@Override
4251
public void receive(TestStepFinished event) {
43-
if (event.testStep.isHook()) {
44-
handleHookResult(event.result);
52+
if (!event.testStep.isHook()) {
53+
handleStepResult(event.testStep, event.result);
4554
} else {
46-
handleStepResult(event.result);
55+
handleHookResult(event.result);
4756
}
4857
}
4958

59+
};
60+
private final EventHandler<TestCaseFinished> testCaseFinishedHandler = new EventHandler<TestCaseFinished>() {
61+
62+
@Override
63+
public void receive(TestCaseFinished event) {
64+
handleTestCaseResult(event.result);
65+
}
66+
5067
};
5168

5269
public JUnitReporter(EventBus bus, boolean strict, JUnitOptions junitOption) {
5370
this.strict = strict;
5471
this.junitOptions = junitOption;
72+
bus.registerHandlerFor(TestCaseStarted.class, testCaseStartedHandler);
5573
bus.registerHandlerFor(TestStepStarted.class, testStepStartedHandler);
5674
bus.registerHandlerFor(TestStepFinished.class, testStepFinishedHandler);
75+
bus.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
5776
}
5877

5978
void startExecutionUnit(PickleRunner pickleRunner, RunNotifier runNotifier) {
6079
this.pickleRunner = pickleRunner;
6180
this.runNotifier = runNotifier;
6281
this.stepNotifier = null;
63-
this.failedStep = false;
64-
this.ignoredStep = false;
6582

6683
pickleRunnerNotifier = new EachTestNotifier(runNotifier, pickleRunner.getDescription());
67-
pickleRunnerNotifier.fireTestStarted();
6884
}
6985

70-
void finishExecutionUnit() {
71-
if (ignoredStep && !failedStep) {
72-
pickleRunnerNotifier.fireTestIgnored();
73-
}
74-
pickleRunnerNotifier.fireTestFinished();
86+
void handleTestCaseStarted() {
87+
pickleRunnerNotifier.fireTestStarted();
88+
stepErrors = new ArrayList<Throwable>();
7589
}
7690

7791
void handleStepStarted(PickleStep step) {
@@ -81,82 +95,88 @@ void handleStepStarted(PickleStep step) {
8195
} else {
8296
stepNotifier = new NoTestNotifier();
8397
}
84-
if (junitOptions.allowStartedIgnored()) {
85-
stepNotifier.fireTestStarted();
86-
}
98+
stepNotifier.fireTestStarted();
8799
}
88100

89101
boolean stepNotifications() {
90102
return junitOptions.stepNotifications();
91103
}
92104

93-
void handleStepResult(Result result) {
105+
void handleStepResult(TestStep testStep, Result result) {
94106
Throwable error = result.getError();
95-
if (result.is(Result.Type.SKIPPED)) {
96-
if (error != null) {
97-
stepNotifier.addFailedAssumption(error);
98-
pickleRunnerNotifier.addFailedAssumption(error);
107+
switch (result.getStatus()) {
108+
case PASSED:
109+
// do nothing
110+
break;
111+
case SKIPPED:
112+
if (error == null) {
113+
error = new SkippedThrowable(NotificationLevel.STEP);
99114
} else {
100-
stepNotifier.fireTestIgnored();
101-
}
102-
} else if (isPendingOrUndefined(result)) {
103-
addFailureOrIgnoreStep(result);
104-
} else {
105-
if (stepNotifier != null) {
106-
//Should only fireTestStarted if not ignored
107-
if (!junitOptions.allowStartedIgnored()) {
108-
stepNotifier.fireTestStarted();
109-
}
110-
if (error != null) {
111-
stepNotifier.addFailure(error);
112-
}
113-
stepNotifier.fireTestFinished();
115+
stepErrors.add(error);
114116
}
115-
if (error != null) {
116-
failedStep = true;
117-
pickleRunnerNotifier.addFailure(error);
117+
stepNotifier.addFailedAssumption(error);
118+
break;
119+
case PENDING:
120+
stepErrors.add(error);
121+
addFailureOrFailedAssumptionDependingOnStrictMode(stepNotifier, error);
122+
break;
123+
case UNDEFINED:
124+
if (error == null) {
125+
error = new UndefinedThrowable();
118126
}
119-
}
127+
stepErrors.add(new UndefinedThrowable(testStep.getStepText()));
128+
addFailureOrFailedAssumptionDependingOnStrictMode(stepNotifier, error);
129+
break;
130+
case FAILED:
131+
stepErrors.add(error);
132+
stepNotifier.addFailure(error);
133+
}
134+
stepNotifier.fireTestFinished();
120135
}
121136

122137
void handleHookResult(Result result) {
123-
if (result.is(Result.Type.FAILED) || (strict && isPending(result.getError()))) {
124-
pickleRunnerNotifier.addFailure(result.getError());
125-
} else if (isPending(result.getError())) {
126-
ignoredStep = true;
138+
if (result.getError() != null) {
139+
stepErrors.add(result.getError());
127140
}
128141
}
129142

130-
boolean useFilenameCompatibleNames() {
131-
return junitOptions.filenameCompatibleNames();
143+
void handleTestCaseResult(Result result) {
144+
switch (result.getStatus()) {
145+
case PASSED:
146+
// do nothing
147+
break;
148+
case SKIPPED:
149+
if (stepErrors.isEmpty()) {
150+
stepErrors.add(new SkippedThrowable(NotificationLevel.SCENARIO));
151+
}
152+
for (Throwable error : stepErrors) {
153+
pickleRunnerNotifier.addFailedAssumption(error);
154+
}
155+
break;
156+
case PENDING:
157+
case UNDEFINED:
158+
for (Throwable error : stepErrors) {
159+
addFailureOrFailedAssumptionDependingOnStrictMode(pickleRunnerNotifier, error);
160+
}
161+
break;
162+
case FAILED:
163+
for (Throwable error : stepErrors) {
164+
pickleRunnerNotifier.addFailure(error);
165+
}
166+
}
167+
pickleRunnerNotifier.fireTestFinished();
132168
}
133169

134-
private boolean isPendingOrUndefined(Result result) {
135-
Throwable error = result.getError();
136-
return result.is(Result.Type.UNDEFINED) || isPending(error);
170+
boolean useFilenameCompatibleNames() {
171+
return junitOptions.filenameCompatibleNames();
137172
}
138173

139-
private void addFailureOrIgnoreStep(Result result) {
174+
private void addFailureOrFailedAssumptionDependingOnStrictMode(TestNotifier notifier, Throwable error) {
140175
if (strict) {
141-
if (!junitOptions.allowStartedIgnored()) {
142-
stepNotifier.fireTestStarted();
143-
}
144-
addFailure(result);
145-
stepNotifier.fireTestFinished();
176+
notifier.addFailure(error);
146177
} else {
147-
ignoredStep = true;
148-
stepNotifier.fireTestIgnored();
149-
}
150-
}
151-
152-
private void addFailure(Result result) {
153-
Throwable error = result.getError();
154-
if (error == null) {
155-
error = new PendingException();
178+
notifier.addFailedAssumption(error);
156179
}
157-
failedStep = true;
158-
stepNotifier.addFailure(error);
159-
pickleRunnerNotifier.addFailure(error);
160180
}
161181

162182
private interface TestNotifier {
@@ -167,13 +187,11 @@ private interface TestNotifier {
167187

168188
void addFailedAssumption(Throwable error);
169189

170-
void fireTestIgnored();
171-
172190
void fireTestFinished();
173191
}
174192

175193

176-
private static final class NoTestNotifier implements TestNotifier {
194+
static final class NoTestNotifier implements TestNotifier {
177195

178196
@Override
179197
public void fireTestStarted() {
@@ -190,11 +208,6 @@ public void addFailedAssumption(Throwable error) {
190208
// Does nothing
191209
}
192210

193-
@Override
194-
public void fireTestIgnored() {
195-
// Does nothing
196-
}
197-
198211
@Override
199212
public void fireTestFinished() {
200213
// Does nothing
@@ -236,9 +249,5 @@ public void fireTestFinished() {
236249
public void fireTestStarted() {
237250
notifier.fireTestStarted(description);
238251
}
239-
240-
public void fireTestIgnored() {
241-
notifier.fireTestIgnored(description);
242-
}
243252
}
244253
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package cucumber.runtime.junit;
2+
3+
public enum NotificationLevel {
4+
SCENARIO,
5+
STEP;
6+
7+
String lowerCaseName() {
8+
return name().toLowerCase();
9+
}
10+
}

junit/src/main/java/cucumber/runtime/junit/PickleRunners.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ public void run(final RunNotifier notifier) {
9393
jUnitReporter.startExecutionUnit(this, notifier);
9494
// This causes runChild to never be called, which seems OK.
9595
runner.runPickle(pickleEvent);
96-
jUnitReporter.finishExecutionUnit();
9796
}
9897

9998
@Override
@@ -139,7 +138,6 @@ public Description describeChild(PickleStep step) {
139138
public void run(final RunNotifier notifier) {
140139
jUnitReporter.startExecutionUnit(this, notifier);
141140
runner.runPickle(pickleEvent);
142-
jUnitReporter.finishExecutionUnit();
143141
}
144142
}
145143

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package cucumber.runtime.junit;
2+
3+
class SkippedThrowable extends Throwable {
4+
private static final long serialVersionUID = 1L;
5+
6+
public SkippedThrowable(NotificationLevel scenarioOrStep) {
7+
super(String.format("This %s is skipped", scenarioOrStep.lowerCaseName()), null, false, false);
8+
}
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package cucumber.runtime.junit;
2+
3+
4+
public class UndefinedThrowable extends Throwable {
5+
private static final long serialVersionUID = 1L;
6+
7+
public UndefinedThrowable() {
8+
super("This step is undefined", null, false, false);
9+
}
10+
11+
public UndefinedThrowable(String stepText) {
12+
super(String.format("The step \"%s\" is undefined", stepText), null, false, false);
13+
}
14+
}

junit/src/main/resources/cucumber/api/junit/OPTIONS.txt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
JUnit Options:
22

33
-h, --help You're looking at it.
4-
--[no-]allow-started-ignored Fire test started before the execution of a
5-
step. This makes it possible to use the
6-
test started and test finished notification
7-
to calculate the execution time of the step.
8-
If the step is pending the test started will
9-
be followed by a test ignored, which can
10-
confuse some listeners.
4+
--[no-]allow-started-ignored Deprecated, has no effect.
115
--[no-]filename-compatible-names Make sure that the names of the test cases
126
only is made up of [A-Za-Z0-9_] so that the
137
names for certain can be used as file names.

0 commit comments

Comments
 (0)