Skip to content

Commit fc6dabc

Browse files
Aniketmpkorstanje
Aniket
authored andcommitted
[Core] Add Before and AfterStep hooks (#1323)
Adds hooks that are invoked before and after a step. The hooks have 'invoke around' semantics. Meaning that if a before step hook is executed the after step hooks will also be executed regardless of the result of the step. If a step did not pass, the following step and its hooks will be skipped. To support the invoke around semantics the TestStep event has been replaced with an interface. And it's concrete implementation split into HookTestStep and PickleStepTestStep. All subclass specific methods in TestStep have been deprecated. When doing a dry run all hooks will be reported. In prior implementations the before and after scenario hooks were unskippable and simply not included. These have been made skippable but will only be skipped on a dry run.
1 parent b142540 commit fc6dabc

File tree

84 files changed

+2048
-903
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+2048
-903
lines changed

android/src/main/java/cucumber/runtime/formatter/AndroidLogcatReporter.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cucumber.runtime.formatter;
22

33
import android.util.Log;
4+
import cucumber.api.PickleStepTestStep;
45
import cucumber.api.event.EventHandler;
56
import cucumber.api.event.EventPublisher;
67
import cucumber.api.event.TestCaseStarted;
@@ -40,8 +41,9 @@ public void receive(TestCaseStarted event) {
4041
private final EventHandler<TestStepStarted> testStepStartedHandler = new EventHandler<TestStepStarted>() {
4142
@Override
4243
public void receive(TestStepStarted event) {
43-
if (!event.testStep.isHook()) {
44-
Log.d(logTag, String.format("%s", event.testStep.getStepText()));
44+
if (event.testStep instanceof PickleStepTestStep) {
45+
PickleStepTestStep testStep = (PickleStepTestStep) event.testStep;
46+
Log.d(logTag, String.format("%s", testStep.getStepText()));
4547
}
4648
}
4749
};

core/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
<dependencies>
1515
<dependency>
16-
<groupId>info.cukes</groupId>
16+
<groupId>io.cucumber</groupId>
1717
<artifactId>cucumber-html</artifactId>
1818
</dependency>
1919
<dependency>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package cucumber.api;
2+
3+
public interface Argument {
4+
Integer getOffset();
5+
6+
String getVal();
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package cucumber.api;
2+
3+
/**
4+
* Hooks are invoked before and after each scenario and before and
5+
* after each gherkin step in a scenario.
6+
*
7+
* @see cucumber.api.event.TestCaseStarted
8+
* @see cucumber.api.event.TestCaseFinished
9+
*/
10+
public interface HookTestStep extends TestStep {
11+
12+
/**
13+
* Returns the hook hook type.
14+
*
15+
* @return the hook type.
16+
*/
17+
HookType getHookType();
18+
19+
}

core/src/main/java/cucumber/api/HookType.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package cucumber.api;
22

33
public enum HookType {
4-
Before, After;
4+
Before, After, BeforeStep, AfterStep;
55

66
@Override
77
public String toString() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package cucumber.api;
2+
3+
import java.util.List;
4+
5+
/**
6+
* A pickle test step matches a line in a Gherkin scenario or background.
7+
*/
8+
public interface PickleStepTestStep extends TestStep {
9+
10+
/**
11+
* The pattern or expression used to match the glue code to the Gherkin step.
12+
*
13+
* @return a pattern or expression
14+
*/
15+
String getPattern();
16+
17+
/**
18+
* The matched Gherkin step as a compiled Pickle
19+
*
20+
* @return the matched step
21+
*/
22+
gherkin.pickles.PickleStep getPickleStep();
23+
24+
25+
/**
26+
* Returns the arguments provided to the step definition.
27+
*
28+
* For example the step definition <code>Given (.*) pickles</code>
29+
* when matched with <code>Given 15 pickles</code> will receive
30+
* as argument <code>"15"</code>
31+
*
32+
* @return argument provided to the step definition
33+
*/
34+
List<cucumber.api.Argument> getDefinitionArgument();
35+
36+
/**
37+
* Returns arguments provided to the Gherkin step. E.g:
38+
* a data table or doc string.
39+
*
40+
* @return arguments provided to the gherkin step.
41+
*/
42+
43+
List<gherkin.pickles.Argument> getStepArgument();
44+
45+
/**
46+
* The line in the feature file defining this step.
47+
*
48+
* @return a line number
49+
*/
50+
int getStepLine();
51+
52+
/**
53+
* A uri to to the feature and line of this step.
54+
*
55+
* @return a uri
56+
*/
57+
String getStepLocation();
58+
59+
/**
60+
* The full text of the Gherkin step.
61+
*
62+
* @return the step text
63+
*/
64+
String getStepText();
65+
}

core/src/main/java/cucumber/api/Result.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@
22

33
import java.io.PrintWriter;
44
import java.io.StringWriter;
5+
import java.util.Comparator;
56

67
public class Result {
8+
9+
public final static Comparator<Result> SEVERITY = new Comparator<Result>() {
10+
11+
@Override
12+
public int compare(Result a, Result b) {
13+
return a.status == b.status ? 0 : a.status.ordinal() > b.status.ordinal() ? 1 : -1;
14+
}
15+
};
16+
717
private static final long serialVersionUID = 1L;
818

9-
private final Result.Type status;
19+
private final Type status;
1020
private final Long duration;
1121
private final Throwable error;
1222
public static final Result SKIPPED = new Result(Result.Type.SKIPPED, null, null);
@@ -85,4 +95,13 @@ private String getErrorMessage(Throwable error) {
8595
error.printStackTrace(printWriter);
8696
return stringWriter.getBuffer().toString();
8797
}
98+
99+
@Override
100+
public String toString() {
101+
return "Result{" +
102+
"status=" + status +
103+
", duration=" + duration +
104+
", error=" + error +
105+
'}';
106+
}
88107
}
+7-83
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,19 @@
11
package cucumber.api;
22

3-
import cucumber.api.event.TestCaseFinished;
4-
import cucumber.api.event.TestCaseStarted;
5-
import cucumber.runner.EventBus;
6-
import cucumber.runtime.ScenarioImpl;
7-
import gherkin.events.PickleEvent;
8-
import gherkin.pickles.PickleLocation;
93
import gherkin.pickles.PickleTag;
104

115
import java.util.List;
126

13-
public class TestCase {
14-
private final PickleEvent pickleEvent;
15-
private final List<TestStep> testSteps;
16-
private final boolean dryRun;
7+
public interface TestCase {
8+
int getLine();
179

18-
/**
19-
* Creates a new instance of a test case.
20-
*
21-
* @param testSteps of the test case
22-
* @param pickleEvent the pickle executed by this test case
23-
* @deprecated not part of the public api
24-
*/
25-
@Deprecated
26-
public TestCase(List<TestStep> testSteps, PickleEvent pickleEvent) {
27-
this(testSteps, pickleEvent, false);
28-
}
10+
String getName();
2911

30-
/**
31-
* Creates a new instance of a test case.
32-
*
33-
* @param testSteps of the test case
34-
* @param pickleEvent the pickle executed by this test case
35-
* @param dryRun skip execution of the test steps
36-
* @deprecated not part of the public api
37-
*/
38-
@Deprecated
39-
public TestCase(List<TestStep> testSteps, PickleEvent pickleEvent, boolean dryRun) {
40-
this.testSteps = testSteps;
41-
this.pickleEvent = pickleEvent;
42-
this.dryRun = dryRun;
43-
}
12+
String getScenarioDesignation();
4413

45-
/**
46-
* Executes the test case.
47-
*
48-
* @param bus to which events should be broadcast
49-
* @deprecated not part of the public api
50-
*/
51-
@Deprecated
52-
public void run(EventBus bus) {
53-
boolean skipNextStep = this.dryRun;
54-
Long startTime = bus.getTime();
55-
bus.send(new TestCaseStarted(startTime, this));
56-
ScenarioImpl scenarioResult = new ScenarioImpl(bus, pickleEvent);
57-
for (TestStep step : testSteps) {
58-
Result stepResult = step.run(bus, pickleEvent.pickle.getLanguage(), scenarioResult, skipNextStep);
59-
if (!stepResult.is(Result.Type.PASSED)) {
60-
skipNextStep = true;
61-
}
62-
scenarioResult.add(stepResult);
63-
}
64-
Long stopTime = bus.getTime();
65-
bus.send(new TestCaseFinished(stopTime, this, new Result(scenarioResult.getStatus(), stopTime - startTime, scenarioResult.getError())));
66-
}
14+
List<PickleTag> getTags();
6715

68-
public List<TestStep> getTestSteps() {
69-
return testSteps;
70-
}
16+
List<TestStep> getTestSteps();
7117

72-
public String getName() {
73-
return pickleEvent.pickle.getName();
74-
}
75-
76-
public String getScenarioDesignation() {
77-
return fileColonLine(pickleEvent.pickle.getLocations().get(0)) + " # " + getName();
78-
}
79-
80-
public String getUri() {
81-
return pickleEvent.uri;
82-
}
83-
84-
public int getLine() {
85-
return pickleEvent.pickle.getLocations().get(0).getLine();
86-
}
87-
88-
private String fileColonLine(PickleLocation location) {
89-
return pickleEvent.uri + ":" + location.getLine();
90-
}
91-
92-
public List<PickleTag> getTags() {
93-
return pickleEvent.pickle.getTags();
94-
}
18+
String getUri();
9519
}

0 commit comments

Comments
 (0)