diff --git a/core/src/main/java/cucumber/runtime/model/CucumberTagStatement.java b/core/src/main/java/cucumber/runtime/model/CucumberTagStatement.java index 60d5e6cf96..ff11be1c4d 100644 --- a/core/src/main/java/cucumber/runtime/model/CucumberTagStatement.java +++ b/core/src/main/java/cucumber/runtime/model/CucumberTagStatement.java @@ -19,13 +19,13 @@ public abstract class CucumberTagStatement extends StepContainer { CucumberTagStatement(CucumberFeature cucumberFeature, TagStatement gherkinModel) { super(cucumberFeature, gherkinModel); this.gherkinModel = gherkinModel; - this.visualName = gherkinModel.getKeyword() + ": " + gherkinModel.getName(); + this.visualName = gherkinModel.getKeyword() + ": " + gherkinModel.getName() + "."+ gherkinModel.getKeyword(); } CucumberTagStatement(CucumberFeature cucumberFeature, TagStatement gherkinModel, Row example) { super(cucumberFeature, gherkinModel); this.gherkinModel = gherkinModel; - this.visualName = "| " + join(example.getCells(), " | ") + " |"; + this.visualName = gherkinModel.getKeyword() + ": " + gherkinModel.getName() +"."+"| " + join(example.getCells(), " | ") + " |"; } protected Set tagsAndInheritedTags() { diff --git a/junit/src/main/java/cucumber/runtime/junit/ExamplesRunner.java b/junit/src/main/java/cucumber/runtime/junit/ExamplesRunner.java index 523d27633b..0987040b76 100644 --- a/junit/src/main/java/cucumber/runtime/junit/ExamplesRunner.java +++ b/junit/src/main/java/cucumber/runtime/junit/ExamplesRunner.java @@ -30,6 +30,11 @@ protected ExamplesRunner(Runtime runtime, CucumberExamples cucumberExamples, JUn } } + @Override + protected List getChildren() { + return super.getChildren(); + } + @Override protected String getName() { return cucumberExamples.getExamples().getKeyword() + ": " + cucumberExamples.getExamples().getName(); diff --git a/junit/src/main/java/cucumber/runtime/junit/ExecutionUnitRunner.java b/junit/src/main/java/cucumber/runtime/junit/ExecutionUnitRunner.java index c2cc9624bd..c25fe3d53d 100644 --- a/junit/src/main/java/cucumber/runtime/junit/ExecutionUnitRunner.java +++ b/junit/src/main/java/cucumber/runtime/junit/ExecutionUnitRunner.java @@ -8,6 +8,7 @@ import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; +import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -36,13 +37,14 @@ protected List getChildren() { @Override public String getName() { - return cucumberScenario.getVisualName(); + return cucumberScenario.getVisualName().substring(cucumberScenario.getVisualName().lastIndexOf('.')+1); } @Override public Description getDescription() { if (description == null) { - description = Description.createSuiteDescription(getName(), cucumberScenario.getGherkinModel()); + //description = createDescription(cucumberScenario.getVisualName(), getName(), cucumberScenario.getGherkinModel()); + description = Description.createSuiteDescription(cucumberScenario.getVisualName(), cucumberScenario.getGherkinModel()); if (cucumberScenario.getCucumberBackground() != null) { for (Step backgroundStep : cucumberScenario.getCucumberBackground().getSteps()) { @@ -70,12 +72,32 @@ public Description getDescription() { protected Description describeChild(Step step) { Description description = stepDescriptions.get(step); if (description == null) { - description = Description.createTestDescription(getName(), step.getKeyword() + step.getName(), step); + description = createDescription(cucumberScenario.getVisualName(), step.getKeyword() + step.getName(), step); stepDescriptions.put(step, description); } return description; } + private static Description createDescription(String className, String name, Serializable uniqueId) { + return Description.createTestDescription(makeClassNameSafe(className), makeNameSafe(name), uniqueId); + } + + private static String makeClassNameSafe(String className) { + String parenthesisSafe = className.replaceAll("\\(","{").replaceAll("\\)","}"); + int indexOfExampleStart = parenthesisSafe.indexOf(".|"); + if (indexOfExampleStart == -1) { + return parenthesisSafe; + } else { + String scenarioPart = parenthesisSafe.substring(0, indexOfExampleStart+1); + String examplePart = parenthesisSafe.substring(indexOfExampleStart+1); + return scenarioPart + examplePart.replaceAll("\\.",","); + } + } + + private static String makeNameSafe(String name) { + return name.replaceAll("\\(","{").replaceAll("\\)","}").replaceAll("\\.",","); + } + @Override public void run(final RunNotifier notifier) { jUnitReporter.startExecutionUnit(this, notifier); diff --git a/junit/src/main/java/cucumber/runtime/junit/JUnitReporter.java b/junit/src/main/java/cucumber/runtime/junit/JUnitReporter.java index cefa1104d9..5016a8a2b1 100644 --- a/junit/src/main/java/cucumber/runtime/junit/JUnitReporter.java +++ b/junit/src/main/java/cucumber/runtime/junit/JUnitReporter.java @@ -44,7 +44,10 @@ public void startExecutionUnit(ExecutionUnitRunner executionUnitRunner, RunNotif this.stepNotifier = null; this.ignoredStep = false; - executionUnitNotifier = new EachTestNotifier(runNotifier, executionUnitRunner.getDescription()); + //We don't want the scenario itself visible in the JUnit results as it is redundant, only its steps + //Provide the executionUnitNotifier with a new (non-null) RunNotifier to effectively + //ignore its notifications + executionUnitNotifier = new EachTestNotifier(new RunNotifier(), executionUnitRunner.getDescription()); executionUnitNotifier.fireTestStarted(); } diff --git a/junit/src/main/java/cucumber/runtime/junit/ScenarioOutlineRunner.java b/junit/src/main/java/cucumber/runtime/junit/ScenarioOutlineRunner.java index b4b801917f..f979288eec 100644 --- a/junit/src/main/java/cucumber/runtime/junit/ScenarioOutlineRunner.java +++ b/junit/src/main/java/cucumber/runtime/junit/ScenarioOutlineRunner.java @@ -3,12 +3,14 @@ import cucumber.runtime.Runtime; import cucumber.runtime.model.CucumberExamples; import cucumber.runtime.model.CucumberScenarioOutline; + import org.junit.runner.Description; import org.junit.runner.Runner; import org.junit.runners.Suite; import org.junit.runners.model.InitializationError; import java.util.ArrayList; +import java.util.List; class ScenarioOutlineRunner extends Suite { private final CucumberScenarioOutline cucumberScenarioOutline; @@ -22,6 +24,11 @@ public ScenarioOutlineRunner(Runtime runtime, CucumberScenarioOutline cucumberSc } } + @Override + protected List getChildren() { + return super.getChildren(); + } + @Override public String getName() { return cucumberScenarioOutline.getVisualName(); diff --git a/junit/src/test/java/cucumber/runtime/junit/ExecutionUnitRunnerTest.java b/junit/src/test/java/cucumber/runtime/junit/ExecutionUnitRunnerTest.java index 345117e80d..59666da5c1 100644 --- a/junit/src/test/java/cucumber/runtime/junit/ExecutionUnitRunnerTest.java +++ b/junit/src/test/java/cucumber/runtime/junit/ExecutionUnitRunnerTest.java @@ -62,7 +62,7 @@ public void shouldIncludeScenarioNameAsClassNameInStepDescriptions() throws Exce Description runnerDescription = runner.getDescription(); Description stepDescription = runnerDescription.getChildren().get(0); - assertEquals("description includes scenario name as class name", runner.getName(), stepDescription.getClassName()); + assertEquals("description includes scenario keyword and name as class name", runner.getDescription().getDisplayName(), stepDescription.getClassName()); assertEquals("description includes step keyword and name as method name", step.getKeyword() + step.getName(), stepDescription.getMethodName()); } } diff --git a/junit/src/test/java/cucumber/runtime/junit/JUnitReporterTest.java b/junit/src/test/java/cucumber/runtime/junit/JUnitReporterTest.java index 1ad142fb37..5eb02d088a 100644 --- a/junit/src/test/java/cucumber/runtime/junit/JUnitReporterTest.java +++ b/junit/src/test/java/cucumber/runtime/junit/JUnitReporterTest.java @@ -3,7 +3,10 @@ import cucumber.api.PendingException; import gherkin.formatter.Formatter; import gherkin.formatter.Reporter; +import gherkin.formatter.model.Match; import gherkin.formatter.model.Result; +import gherkin.formatter.model.Step; + import org.junit.Test; import org.junit.internal.runners.model.EachTestNotifier; import org.junit.runner.Description; @@ -14,6 +17,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -23,6 +27,7 @@ public class JUnitReporterTest { private JUnitReporter jUnitReporter; private RunNotifier runNotifier; + private ExecutionUnitRunner executionUnitRunner; @Test public void resultWithError() { @@ -34,6 +39,10 @@ public void resultWithError() { Description description = mock(Description.class); createRunNotifier(description); + when(executionUnitRunner.describeChild(any(Step.class))).thenReturn(description); + jUnitReporter.step(mock(Step.class)); + jUnitReporter.match(mock(Match.class)); + jUnitReporter.result(result); ArgumentCaptor failureArgumentCaptor = ArgumentCaptor.forClass(Failure.class); @@ -159,7 +168,7 @@ private void createDefaultRunNotifier() { private void createRunNotifier(Description description) { runNotifier = mock(RunNotifier.class); - ExecutionUnitRunner executionUnitRunner = mock(ExecutionUnitRunner.class); + executionUnitRunner = mock(ExecutionUnitRunner.class); when(executionUnitRunner.getDescription()).thenReturn(description); jUnitReporter.startExecutionUnit(executionUnitRunner, runNotifier); } diff --git a/junit/src/test/java/cucumber/runtime/junit/ScenarioOutlineRunnerTest.java b/junit/src/test/java/cucumber/runtime/junit/ScenarioOutlineRunnerTest.java new file mode 100644 index 0000000000..ae100eb058 --- /dev/null +++ b/junit/src/test/java/cucumber/runtime/junit/ScenarioOutlineRunnerTest.java @@ -0,0 +1,47 @@ +package cucumber.runtime.junit; + +import java.util.Collections; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.Description; + +import cucumber.runtime.io.ClasspathResourceLoader; +import cucumber.runtime.model.CucumberFeature; +import cucumber.runtime.model.CucumberScenario; +import cucumber.runtime.model.CucumberScenarioOutline; +import gherkin.formatter.model.Step; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +public class ScenarioOutlineRunnerTest { + @Test + public void shouldIncludeExampleRowAsClassNameInStepDescriptions() throws Exception { + List features = CucumberFeature.load( + new ClasspathResourceLoader(this.getClass().getClassLoader()), + asList("cucumber/runtime/junit/feature_with_same_steps_in_different_scenarios.feature"), + Collections.emptyList() + ); + + ScenarioOutlineRunner runner = new ScenarioOutlineRunner( + null, + (CucumberScenarioOutline) features.get(0).getFeatureElements().get(2), + null + ); + + // fish out the data from runner + ExecutionUnitRunner executionUnitRunner = ((ExecutionUnitRunner)((ExamplesRunner)(runner.getChildren().get(0))).getChildren().get(0)); + Step step = executionUnitRunner.getChildren().get(0); + Description runnerDescription = executionUnitRunner.getDescription(); + Description stepDescription = runnerDescription.getChildren().get(0); + + System.out.println(runner.getDescription().getDisplayName()); + assertEquals( + "description includes scenario outline keyword and example row as class name, and is properly escaped", + "Scenario Outline: third.| {example} 1,2 |", stepDescription.getClassName()); + assertEquals("description includes step keyword and name as method name, and is properly escaped", "When {example} 1,2 {step}", + stepDescription.getMethodName()); + } +} diff --git a/junit/src/test/resources/cucumber/runtime/junit/feature_with_same_steps_in_different_scenarios.feature b/junit/src/test/resources/cucumber/runtime/junit/feature_with_same_steps_in_different_scenarios.feature index 9b15d8fbb4..c9278fd531 100644 --- a/junit/src/test/resources/cucumber/runtime/junit/feature_with_same_steps_in_different_scenarios.feature +++ b/junit/src/test/resources/cucumber/runtime/junit/feature_with_same_steps_in_different_scenarios.feature @@ -6,3 +6,11 @@ Feature: In cucumber.junit Scenario: second When step Then another step + + Scenario Outline: third + When (step) + Then another step + + Examples: + | example | + | (example) 1.2 | \ No newline at end of file