Skip to content

Commit

Permalink
[Core] Separate dry-run and skip execution strategies
Browse files Browse the repository at this point in the history
  • Loading branch information
mpkorstanje committed Sep 4, 2020
1 parent 5a1794c commit b855ba9
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 72 deletions.
34 changes: 34 additions & 0 deletions core/src/main/java/io/cucumber/core/runner/ExecutionMode.java
@@ -0,0 +1,34 @@
package io.cucumber.core.runner;

import io.cucumber.plugin.event.Status;

enum ExecutionMode {

RUN {
@Override
Status execute(StepDefinitionMatch stepDefinitionMatch, TestCaseState state) throws Throwable {
stepDefinitionMatch.runStep(state);
return Status.PASSED;
}

},
DRY_RUN {
@Override
Status execute(StepDefinitionMatch stepDefinitionMatch, TestCaseState state) throws Throwable {
stepDefinitionMatch.dryRunStep(state);
return Status.PASSED;
}
},
SKIP {
@Override
Status execute(StepDefinitionMatch stepDefinitionMatch, TestCaseState state) {
return Status.SKIPPED;
}
};

abstract Status execute(StepDefinitionMatch stepDefinitionMatch, TestCaseState state) throws Throwable;

ExecutionMode next(ExecutionMode current) {
return current == SKIP ? current : this;
}
}
17 changes: 11 additions & 6 deletions core/src/main/java/io/cucumber/core/runner/PickleStepTestStep.java
Expand Up @@ -39,20 +39,25 @@ final class PickleStepTestStep extends TestStep implements io.cucumber.plugin.ev
}

@Override
boolean run(TestCase testCase, EventBus bus, TestCaseState state, boolean skipSteps) {
boolean skipNextStep = skipSteps;
ExecutionMode run(TestCase testCase, EventBus bus, TestCaseState state, ExecutionMode executionMode) {
ExecutionMode nextExecutionMode = executionMode;

for (HookTestStep before : beforeStepHookSteps) {
skipNextStep |= before.run(testCase, bus, state, skipSteps);
nextExecutionMode = before
.run(testCase, bus, state, executionMode)
.next(nextExecutionMode);
}

skipNextStep |= super.run(testCase, bus, state, skipNextStep);
nextExecutionMode = super.run(testCase, bus, state, nextExecutionMode)
.next(nextExecutionMode);

for (HookTestStep after : afterStepHookSteps) {
skipNextStep |= after.run(testCase, bus, state, skipSteps);
nextExecutionMode = after
.run(testCase, bus, state, executionMode)
.next(nextExecutionMode);
}

return skipNextStep;
return nextExecutionMode;
}

List<HookTestStep> getBeforeStepHookSteps() {
Expand Down
20 changes: 14 additions & 6 deletions core/src/main/java/io/cucumber/core/runner/TestCase.java
Expand Up @@ -22,6 +22,8 @@
import java.util.List;
import java.util.UUID;

import static io.cucumber.core.runner.ExecutionMode.DRY_RUN;
import static io.cucumber.core.runner.ExecutionMode.RUN;
import static io.cucumber.core.runner.TestStepResultStatus.from;
import static io.cucumber.messages.TimeConversion.javaDurationToDuration;
import static io.cucumber.messages.TimeConversion.javaInstantToTimestamp;
Expand All @@ -32,7 +34,7 @@ final class TestCase implements io.cucumber.plugin.event.TestCase {

private final Pickle pickle;
private final List<PickleStepTestStep> testSteps;
private final boolean dryRun;
private final ExecutionMode executionMode;
private final List<HookTestStep> beforeHooks;
private final List<HookTestStep> afterHooks;
private final UUID id;
Expand All @@ -49,7 +51,7 @@ final class TestCase implements io.cucumber.plugin.event.TestCase {
this.beforeHooks = beforeHooks;
this.afterHooks = afterHooks;
this.pickle = pickle;
this.dryRun = dryRun;
this.executionMode = dryRun ? DRY_RUN : RUN;
}

private static StepMatchArgument.Group makeMessageGroup(
Expand Down Expand Up @@ -82,7 +84,7 @@ private static String toString(Throwable error) {
}

void run(EventBus bus) {
boolean skipNextStep = this.dryRun;
ExecutionMode nextExecutionMode = this.executionMode;
emitTestCaseMessage(bus);

Instant start = bus.getInstant();
Expand All @@ -92,15 +94,21 @@ void run(EventBus bus) {
TestCaseState state = new TestCaseState(bus, executionId, this);

for (HookTestStep before : beforeHooks) {
skipNextStep |= before.run(this, bus, state, dryRun);
nextExecutionMode = before
.run(this, bus, state, executionMode)
.next(nextExecutionMode);
}

for (PickleStepTestStep step : testSteps) {
skipNextStep |= step.run(this, bus, state, skipNextStep);
nextExecutionMode = step
.run(this, bus, state, nextExecutionMode)
.next(nextExecutionMode);
}

for (HookTestStep after : afterHooks) {
after.run(this, bus, state, dryRun);
nextExecutionMode = after
.run(this, bus, state, executionMode)
.next(nextExecutionMode);
}

Instant stop = bus.getInstant();
Expand Down
17 changes: 6 additions & 11 deletions core/src/main/java/io/cucumber/core/runner/TestStep.java
Expand Up @@ -17,6 +17,7 @@
import java.util.Arrays;
import java.util.UUID;

import static io.cucumber.core.runner.ExecutionMode.SKIP;
import static io.cucumber.core.runner.TestStepResultStatus.from;
import static io.cucumber.messages.TimeConversion.javaDurationToDuration;
import static io.cucumber.messages.TimeConversion.javaInstantToTimestamp;
Expand Down Expand Up @@ -53,14 +54,14 @@ public UUID getId() {
return id;
}

boolean run(TestCase testCase, EventBus bus, TestCaseState state, boolean skipSteps) {
ExecutionMode run(TestCase testCase, EventBus bus, TestCaseState state, ExecutionMode executionMode) {
Instant startTime = bus.getInstant();
emitTestStepStarted(testCase, bus, state.getTestExecutionId(), startTime);

Status status;
Throwable error = null;
try {
status = executeStep(state, skipSteps);
status = executeStep(state, executionMode);
} catch (Throwable t) {
error = t;
status = mapThrowableToStatus(t);
Expand All @@ -72,7 +73,7 @@ boolean run(TestCase testCase, EventBus bus, TestCaseState state, boolean skipSt

emitTestStepFinished(testCase, bus, state.getTestExecutionId(), stopTime, duration, result);

return !result.getStatus().is(Status.PASSED);
return result.getStatus().is(Status.PASSED) ? executionMode : SKIP;
}

private void emitTestStepStarted(TestCase testCase, EventBus bus, UUID textExecutionId, Instant startTime) {
Expand All @@ -85,16 +86,10 @@ private void emitTestStepStarted(TestCase testCase, EventBus bus, UUID textExecu
.build());
}

private Status executeStep(TestCaseState state, boolean skipSteps) throws Throwable {
private Status executeStep(TestCaseState state, ExecutionMode executionMode) throws Throwable {
state.setCurrentTestStepId(id);
try {
if (!skipSteps) {
stepDefinitionMatch.runStep(state);
return Status.PASSED;
} else {
stepDefinitionMatch.dryRunStep(state);
return Status.SKIPPED;
}
return executionMode.execute(stepDefinitionMatch, state);
} finally {
state.clearCurrentTestStepId();
}
Expand Down
Expand Up @@ -62,7 +62,7 @@ void testScenarioWithUndefinedSteps() {
" <message>\n" +
" <![CDATA[When step...................................................................undefined\n"
+
"Then step...................................................................undefined\n" +
"Then step...................................................................skipped\n" +
"]]>\n" +
" </message>\n" +
" <full-stacktrace>\n" +
Expand Down Expand Up @@ -231,9 +231,9 @@ void testScenarioWithBackground() {
" <message>\n" +
" <![CDATA[When background.............................................................undefined\n"
+
"Then background.............................................................undefined\n" +
"When step...................................................................undefined\n" +
"Then step...................................................................undefined\n" +
"Then background.............................................................skipped\n" +
"When step...................................................................skipped\n" +
"Then step...................................................................skipped\n" +
"]]>\n" +
" </message>\n" +
" <full-stacktrace>\n" +
Expand Down Expand Up @@ -281,7 +281,7 @@ void testScenarioOutlineWithExamples() {
" <message>\n" +
" <![CDATA[When step...................................................................undefined\n"
+
"Then step...................................................................undefined\n" +
"Then step...................................................................skipped\n" +
"]]>\n" +
" </message>\n" +
" <full-stacktrace>\n" +
Expand All @@ -295,7 +295,7 @@ void testScenarioOutlineWithExamples() {
" <message>\n" +
" <![CDATA[When step...................................................................undefined\n"
+
"Then step...................................................................undefined\n" +
"Then step...................................................................skipped\n" +
"]]>\n" +
" </message>\n" +
" <full-stacktrace>\n" +
Expand Down
23 changes: 15 additions & 8 deletions core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java
Expand Up @@ -54,7 +54,7 @@ void init() {

@Test
void run_does_run() {
step.run(testCase, bus, state, false);
step.run(testCase, bus, state, ExecutionMode.RUN);

InOrder order = inOrder(bus, hookDefintion);
order.verify(bus).send(isA(TestStepStarted.class));
Expand All @@ -64,7 +64,7 @@ void run_does_run() {

@Test
void run_does_dry_run() {
step.run(testCase, bus, state, true);
step.run(testCase, bus, state, ExecutionMode.DRY_RUN);

InOrder order = inOrder(bus, hookDefintion);
order.verify(bus).send(isA(TestStepStarted.class));
Expand All @@ -73,17 +73,24 @@ void run_does_dry_run() {
}

@Test
void result_is_passed_when_step_definition_does_not_throw_exception() {
boolean skipNextStep = step.run(testCase, bus, state, false);
assertFalse(skipNextStep);
void next_execution_mode_is_run_when_step_passes() {
ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN);
assertThat(nextExecutionMode, is(ExecutionMode.RUN));
assertThat(state.getStatus(), is(equalTo(PASSED)));
}

@Test
void result_is_skipped_when_skip_step_is_skip_all_skipable() {
boolean skipNextStep = step.run(testCase, bus, state, true);
assertTrue(skipNextStep);
void next_execution_mode_is_skip_when_step_is_skipped() {
ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.SKIP);
assertThat(nextExecutionMode, is(ExecutionMode.SKIP));
assertThat(state.getStatus(), is(equalTo(SKIPPED)));
}

@Test
void next_execution_mode_is_dry_run_when_step_passes_dry_run() {
ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.DRY_RUN);
assertThat(nextExecutionMode, is(ExecutionMode.DRY_RUN));
assertThat(state.getStatus(), is(equalTo(PASSED)));
}

}

0 comments on commit b855ba9

Please sign in to comment.