diff --git a/junit/src/main/java/io/cucumber/junit/Cucumber.java b/junit/src/main/java/io/cucumber/junit/Cucumber.java index 75297aacb7..9978decbb6 100644 --- a/junit/src/main/java/io/cucumber/junit/Cucumber.java +++ b/junit/src/main/java/io/cucumber/junit/Cucumber.java @@ -5,8 +5,6 @@ import io.cucumber.core.filter.Filters; import io.cucumber.core.gherkin.Feature; import io.cucumber.core.gherkin.Pickle; -import io.cucumber.core.logging.Logger; -import io.cucumber.core.logging.LoggerFactory; import io.cucumber.core.options.Constants; import io.cucumber.core.options.CucumberOptionsAnnotationParser; import io.cucumber.core.options.CucumberProperties; @@ -40,10 +38,14 @@ import java.time.Clock; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.function.Predicate; import java.util.function.Supplier; +import static io.cucumber.junit.FileNameCompatibleNames.uniqueSuffix; +import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toList; /** @@ -88,8 +90,6 @@ @API(status = API.Status.STABLE) public final class Cucumber extends ParentRunner> { - private static final Logger log = LoggerFactory.getLogger(Cucumber.class); - private final List> children; private final EventBus bus; private final List features; @@ -171,8 +171,14 @@ public Cucumber(Class clazz) throws InitializationError { objectFactorySupplier, typeRegistryConfigurerSupplier); this.context = new CucumberExecutionContext(bus, exitStatus, runnerSupplier); Predicate filters = new Filters(runtimeOptions); + + Map, List> groupedByName = features.stream() + .collect(groupingBy(Feature::getName)); this.children = features.stream() - .map(feature -> FeatureRunner.create(feature, filters, runnerSupplier, junitOptions)) + .map(feature -> { + Integer uniqueSuffix = uniqueSuffix(groupedByName, feature, Feature::getName); + return FeatureRunner.create(feature, uniqueSuffix, filters, runnerSupplier, junitOptions); + }) .filter(runner -> !runner.isEmpty()) .collect(toList()); } diff --git a/junit/src/main/java/io/cucumber/junit/FeatureRunner.java b/junit/src/main/java/io/cucumber/junit/FeatureRunner.java index e730dcbf7b..0911fe0e20 100644 --- a/junit/src/main/java/io/cucumber/junit/FeatureRunner.java +++ b/junit/src/main/java/io/cucumber/junit/FeatureRunner.java @@ -14,11 +14,14 @@ import java.io.Serializable; import java.net.URI; import java.util.List; +import java.util.Map; import java.util.function.Predicate; import static io.cucumber.junit.FileNameCompatibleNames.createName; +import static io.cucumber.junit.FileNameCompatibleNames.uniqueSuffix; import static io.cucumber.junit.PickleRunners.withNoStepDescriptions; import static io.cucumber.junit.PickleRunners.withStepDescriptions; +import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toList; final class FeatureRunner extends ParentRunner { @@ -26,26 +29,40 @@ final class FeatureRunner extends ParentRunner { private final List children; private final Feature feature; private final JUnitOptions options; + private final Integer uniqueSuffix; private Description description; - private FeatureRunner(Feature feature, Predicate filter, RunnerSupplier runners, JUnitOptions options) + private FeatureRunner( + Feature feature, Integer uniqueSuffix, Predicate filter, RunnerSupplier runners, + JUnitOptions options + ) throws InitializationError { super((Class) null); this.feature = feature; + this.uniqueSuffix = uniqueSuffix; this.options = options; - String name = feature.getName().orElse("EMPTY_NAME"); - this.children = feature.getPickles().stream() - .filter(filter).map(pickle -> options.stepNotifications() - ? withStepDescriptions(runners, pickle, options) - : withNoStepDescriptions(name, runners, pickle, options)) + + Map> groupedByName = feature.getPickles().stream() + .collect(groupingBy(Pickle::getName)); + this.children = feature.getPickles() + .stream() + .filter(filter) + .map(pickle -> { + String featureName = getName(); + Integer exampleId = uniqueSuffix(groupedByName, pickle, Pickle::getName); + return options.stepNotifications() + ? withStepDescriptions(runners, pickle, exampleId, options) + : withNoStepDescriptions(featureName, runners, pickle, exampleId, options); + }) .collect(toList()); } static FeatureRunner create( - Feature feature, Predicate filter, RunnerSupplier runners, JUnitOptions options + Feature feature, Integer uniqueSuffix, Predicate filter, RunnerSupplier runners, + JUnitOptions options ) { try { - return new FeatureRunner(feature, filter, runners, options); + return new FeatureRunner(feature, uniqueSuffix, filter, runners, options); } catch (InitializationError e) { throw new CucumberException("Failed to create scenario runner", e); } @@ -89,7 +106,7 @@ public String toString() { @Override protected String getName() { String name = feature.getName().orElse("EMPTY_NAME"); - return createName(name, options.filenameCompatibleNames()); + return createName(name, uniqueSuffix, options.filenameCompatibleNames()); } @Override diff --git a/junit/src/main/java/io/cucumber/junit/FileNameCompatibleNames.java b/junit/src/main/java/io/cucumber/junit/FileNameCompatibleNames.java index 9e6ac714b6..cae9185a1f 100644 --- a/junit/src/main/java/io/cucumber/junit/FileNameCompatibleNames.java +++ b/junit/src/main/java/io/cucumber/junit/FileNameCompatibleNames.java @@ -1,12 +1,22 @@ package io.cucumber.junit; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + final class FileNameCompatibleNames { + static String createName(String name, Integer uniqueSuffix, boolean useFilenameCompatibleNames) { + if (uniqueSuffix == null) { + return createName(name, useFilenameCompatibleNames); + } + return createName(name + " #" + uniqueSuffix + "", useFilenameCompatibleNames); + } + static String createName(final String name, boolean useFilenameCompatibleNames) { if (useFilenameCompatibleNames) { return makeNameFilenameCompatible(name); } - return name; } @@ -14,4 +24,10 @@ private static String makeNameFilenameCompatible(String name) { return name.replaceAll("[^A-Za-z0-9_]", "_"); } + static Integer uniqueSuffix(Map> groupedByName, V pickle, Function nameOf) { + List withSameName = groupedByName.get(nameOf.apply(pickle)); + boolean makeNameUnique = withSameName.size() > 1; + return makeNameUnique ? withSameName.indexOf(pickle) + 1 : null; + } + } diff --git a/junit/src/main/java/io/cucumber/junit/PickleRunners.java b/junit/src/main/java/io/cucumber/junit/PickleRunners.java index aac157795e..11074ed685 100644 --- a/junit/src/main/java/io/cucumber/junit/PickleRunners.java +++ b/junit/src/main/java/io/cucumber/junit/PickleRunners.java @@ -21,18 +21,21 @@ final class PickleRunners { - static PickleRunner withStepDescriptions(RunnerSupplier runnerSupplier, Pickle pickle, JUnitOptions options) { + static PickleRunner withStepDescriptions( + RunnerSupplier runnerSupplier, Pickle pickle, Integer uniqueSuffix, JUnitOptions options + ) { try { - return new WithStepDescriptions(runnerSupplier, pickle, options); + return new WithStepDescriptions(runnerSupplier, pickle, uniqueSuffix, options); } catch (InitializationError e) { throw new CucumberException("Failed to create scenario runner", e); } } static PickleRunner withNoStepDescriptions( - String featureName, RunnerSupplier runnerSupplier, Pickle pickle, JUnitOptions jUnitOptions + String featureName, RunnerSupplier runnerSupplier, Pickle pickle, Integer uniqueSuffix, + JUnitOptions jUnitOptions ) { - return new NoStepDescriptions(featureName, runnerSupplier, pickle, jUnitOptions); + return new NoStepDescriptions(featureName, runnerSupplier, pickle, uniqueSuffix, jUnitOptions); } interface PickleRunner { @@ -51,14 +54,18 @@ static class WithStepDescriptions extends ParentRunner implements PickleRu private final Pickle pickle; private final JUnitOptions jUnitOptions; private final Map stepDescriptions = new HashMap<>(); + private final Integer uniqueSuffix; private Description description; - WithStepDescriptions(RunnerSupplier runnerSupplier, Pickle pickle, JUnitOptions jUnitOptions) + WithStepDescriptions( + RunnerSupplier runnerSupplier, Pickle pickle, Integer uniqueSuffix, JUnitOptions jUnitOptions + ) throws InitializationError { super((Class) null); this.runnerSupplier = runnerSupplier; this.pickle = pickle; this.jUnitOptions = jUnitOptions; + this.uniqueSuffix = uniqueSuffix; } @Override @@ -70,7 +77,7 @@ protected List getChildren() { @Override protected String getName() { - return createName(pickle.getName(), jUnitOptions.filenameCompatibleNames()); + return createName(pickle.getName(), uniqueSuffix, jUnitOptions.filenameCompatibleNames()); } @Override @@ -86,8 +93,9 @@ public Description getDescription() { public Description describeChild(Step step) { Description description = stepDescriptions.get(step); if (description == null) { - String testName = createName(step.getText(), jUnitOptions.filenameCompatibleNames()); - description = Description.createTestDescription(getName(), testName, new PickleStepId(pickle, step)); + String className = getName(); + String name = createName(step.getText(), jUnitOptions.filenameCompatibleNames()); + description = Description.createTestDescription(className, name, new PickleStepId(pickle, step)); stepDescriptions.put(step, description); } return description; @@ -120,15 +128,18 @@ static final class NoStepDescriptions implements PickleRunner { private final RunnerSupplier runnerSupplier; private final Pickle pickle; private final JUnitOptions jUnitOptions; + private final Integer uniqueSuffix; private Description description; NoStepDescriptions( - String featureName, RunnerSupplier runnerSupplier, Pickle pickle, JUnitOptions jUnitOptions + String featureName, RunnerSupplier runnerSupplier, Pickle pickle, Integer uniqueSuffix, + JUnitOptions jUnitOptions ) { this.featureName = featureName; this.runnerSupplier = runnerSupplier; this.pickle = pickle; this.jUnitOptions = jUnitOptions; + this.uniqueSuffix = uniqueSuffix; } @Override @@ -145,7 +156,7 @@ public void run(final RunNotifier notifier) { public Description getDescription() { if (description == null) { String className = createName(featureName, jUnitOptions.filenameCompatibleNames()); - String name = createName(pickle.getName(), jUnitOptions.filenameCompatibleNames()); + String name = createName(pickle.getName(), uniqueSuffix, jUnitOptions.filenameCompatibleNames()); description = Description.createTestDescription(className, name, new PickleId(pickle)); } return description; diff --git a/junit/src/test/java/io/cucumber/junit/CucumberTest.java b/junit/src/test/java/io/cucumber/junit/CucumberTest.java index d265611a45..3d5ed1185a 100644 --- a/junit/src/test/java/io/cucumber/junit/CucumberTest.java +++ b/junit/src/test/java/io/cucumber/junit/CucumberTest.java @@ -53,14 +53,14 @@ void ensureOriginalDirectory() { @Test void finds_features_based_on_implicit_package() throws InitializationError { Cucumber cucumber = new Cucumber(ImplicitFeatureAndGluePath.class); - assertThat(cucumber.getChildren().size(), is(equalTo(6))); + assertThat(cucumber.getChildren().size(), is(equalTo(7))); assertThat(cucumber.getChildren().get(1).getDescription().getDisplayName(), is(equalTo("Feature A"))); } @Test void finds_features_based_on_explicit_root_package() throws InitializationError { Cucumber cucumber = new Cucumber(ExplicitFeaturePath.class); - assertThat(cucumber.getChildren().size(), is(equalTo(6))); + assertThat(cucumber.getChildren().size(), is(equalTo(7))); assertThat(cucumber.getChildren().get(1).getDescription().getDisplayName(), is(equalTo("Feature A"))); } @@ -104,15 +104,19 @@ void cucumber_can_run_features_in_parallel() throws Exception { Request.classes(computer, ValidEmpty.class).getRunner().run(notifier); { InOrder order = Mockito.inOrder(listener); - order.verify(listener).testStarted(argThat(new DescriptionMatcher("Followed by some examples(Feature A)"))); + + order.verify(listener) + .testStarted(argThat(new DescriptionMatcher("Followed by some examples #1(Feature A)"))); + order.verify(listener) + .testFinished(argThat(new DescriptionMatcher("Followed by some examples #1(Feature A)"))); order.verify(listener) - .testFinished(argThat(new DescriptionMatcher("Followed by some examples(Feature A)"))); - order.verify(listener).testStarted(argThat(new DescriptionMatcher("Followed by some examples(Feature A)"))); + .testStarted(argThat(new DescriptionMatcher("Followed by some examples #2(Feature A)"))); order.verify(listener) - .testFinished(argThat(new DescriptionMatcher("Followed by some examples(Feature A)"))); - order.verify(listener).testStarted(argThat(new DescriptionMatcher("Followed by some examples(Feature A)"))); + .testFinished(argThat(new DescriptionMatcher("Followed by some examples #2(Feature A)"))); order.verify(listener) - .testFinished(argThat(new DescriptionMatcher("Followed by some examples(Feature A)"))); + .testStarted(argThat(new DescriptionMatcher("Followed by some examples #3(Feature A)"))); + order.verify(listener) + .testFinished(argThat(new DescriptionMatcher("Followed by some examples #3(Feature A)"))); } { InOrder order = Mockito.inOrder(listener); @@ -120,12 +124,38 @@ void cucumber_can_run_features_in_parallel() throws Exception { order.verify(listener).testFinished(argThat(new DescriptionMatcher("A(Feature B)"))); order.verify(listener).testStarted(argThat(new DescriptionMatcher("B(Feature B)"))); order.verify(listener).testFinished(argThat(new DescriptionMatcher("B(Feature B)"))); - order.verify(listener).testStarted(argThat(new DescriptionMatcher("C(Feature B)"))); - order.verify(listener).testFinished(argThat(new DescriptionMatcher("C(Feature B)"))); - order.verify(listener).testStarted(argThat(new DescriptionMatcher("C(Feature B)"))); - order.verify(listener).testFinished(argThat(new DescriptionMatcher("C(Feature B)"))); - order.verify(listener).testStarted(argThat(new DescriptionMatcher("C(Feature B)"))); - order.verify(listener).testFinished(argThat(new DescriptionMatcher("C(Feature B)"))); + order.verify(listener).testStarted(argThat(new DescriptionMatcher("C #1(Feature B)"))); + order.verify(listener).testFinished(argThat(new DescriptionMatcher("C #1(Feature B)"))); + order.verify(listener).testStarted(argThat(new DescriptionMatcher("C #2(Feature B)"))); + order.verify(listener).testFinished(argThat(new DescriptionMatcher("C #2(Feature B)"))); + order.verify(listener).testStarted(argThat(new DescriptionMatcher("C #3(Feature B)"))); + order.verify(listener).testFinished(argThat(new DescriptionMatcher("C #3(Feature B)"))); + } + } + + @Test + void cucumber_distinguishes_between_identical_features() throws Exception { + RunNotifier notifier = new RunNotifier(); + RunListener listener = Mockito.mock(RunListener.class); + notifier.addListener(listener); + Request.classes(ValidEmpty.class).getRunner().run(notifier); + { + InOrder order = Mockito.inOrder(listener); + + order.verify(listener) + .testStarted( + argThat(new DescriptionMatcher("A single scenario(A feature with a single scenario #1)"))); + order.verify(listener) + .testFinished( + argThat(new DescriptionMatcher("A single scenario(A feature with a single scenario #1)"))); + + order.verify(listener) + .testStarted( + argThat(new DescriptionMatcher("A single scenario(A feature with a single scenario #2)"))); + order.verify(listener) + .testFinished( + argThat(new DescriptionMatcher("A single scenario(A feature with a single scenario #2)"))); + } } diff --git a/junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java b/junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java index ca0deb1d8e..a6f46437c9 100644 --- a/junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java +++ b/junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java @@ -4,6 +4,7 @@ import io.cucumber.core.filter.Filters; import io.cucumber.core.gherkin.Feature; import io.cucumber.core.options.RuntimeOptions; +import io.cucumber.core.options.RuntimeOptionsBuilder; import io.cucumber.core.runtime.BackendSupplier; import io.cucumber.core.runtime.ObjectFactoryServiceLoader; import io.cucumber.core.runtime.ObjectFactorySupplier; @@ -12,6 +13,7 @@ import io.cucumber.core.runtime.SingletonObjectFactorySupplier; import io.cucumber.core.runtime.ThreadLocalRunnerSupplier; import io.cucumber.core.runtime.TimeServiceEventBus; +import io.cucumber.tagexpressions.TagExpressionParser; import org.junit.jupiter.api.Test; import org.junit.runner.Description; import org.junit.runner.notification.Failure; @@ -121,7 +123,7 @@ public Instant instant() { classLoader, runtimeOptions); ThreadLocalRunnerSupplier runnerSupplier = new ThreadLocalRunnerSupplier(runtimeOptions, bus, backendSupplier, objectFactory, typeRegistrySupplier); - return FeatureRunner.create(feature, filters, runnerSupplier, junitOption); + return FeatureRunner.create(feature, null, filters, runnerSupplier, junitOption); } @Test @@ -365,7 +367,7 @@ void should_notify_of_failure_to_create_runners_and_request_test_execution_to_st throw illegalStateException; }; - FeatureRunner featureRunner = FeatureRunner.create(feature, filters, runnerSupplier, new JUnitOptions()); + FeatureRunner featureRunner = FeatureRunner.create(feature, null, filters, runnerSupplier, new JUnitOptions()); RunNotifier notifier = mock(RunNotifier.class); PickleRunners.PickleRunner pickleRunner = featureRunner.getChildren().get(0); @@ -383,4 +385,31 @@ void should_notify_of_failure_to_create_runners_and_request_test_execution_to_st order.verify(notifier).fireTestFinished(description); } + @Test + void should_filter_pickles() { + Feature feature = TestPickleBuilder.parseFeature("path/test.feature", "" + + "Feature: feature name\n" + + " Scenario: scenario_1 name\n" + + " Given step #1\n" + + " @tag\n" + + " Scenario: scenario_2 name\n" + + " Given step #1\n" + + ); + + RuntimeOptions options = new RuntimeOptionsBuilder() + .addTagFilter(TagExpressionParser.parse("@tag")) + .build(); + Filters filters = new Filters(options); + + IllegalStateException illegalStateException = new IllegalStateException(); + RunnerSupplier runnerSupplier = () -> { + throw illegalStateException; + }; + + FeatureRunner featureRunner = FeatureRunner.create(feature, null, filters, runnerSupplier, new JUnitOptions()); + assertThat(featureRunner.getChildren().size(), is(1)); + assertThat(featureRunner.getChildren().get(0).getDescription().getDisplayName(), is("scenario_2 name(feature name)")); + } + } diff --git a/junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java b/junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java index ac949f4a79..2bcbe63157 100644 --- a/junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java +++ b/junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java @@ -25,6 +25,7 @@ void shouldUseScenarioNameWithFeatureNameAsClassNameForDisplayName() { "feature name", mock(RunnerSupplier.class), pickles.get(0), + null, createJunitOptions()); assertThat(runner.getDescription().getDisplayName(), is(equalTo("scenario name(feature name)"))); @@ -45,6 +46,7 @@ void shouldConvertTextFromFeatureFileForNamesWithFilenameCompatibleNameOption() "feature name", mock(RunnerSupplier.class), pickles.get(0), + null, createFileNameCompatibleJUnitOptions()); assertThat(runner.getDescription().getDisplayName(), is(equalTo("scenario_name(feature_name)"))); @@ -66,6 +68,7 @@ void shouldConvertTextFromFeatureFileWithRussianLanguage() { "имя функции", mock(RunnerSupplier.class), pickles.get(0), + null, createFileNameCompatibleJUnitOptions()); assertThat(runner.getDescription().getDisplayName(), is(equalTo("____________(___________)"))); diff --git a/junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java b/junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java index 4589b753ab..85b71b931a 100644 --- a/junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java +++ b/junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java @@ -34,6 +34,7 @@ void shouldAssignUnequalDescriptionsToDifferentOccurrencesOfSameStepInAScenario( WithStepDescriptions runner = (WithStepDescriptions) PickleRunners.withStepDescriptions( mock(RunnerSupplier.class), pickles.get(0), + null, createJunitOptions()); // fish out the two occurrences of the same step and check whether we @@ -69,6 +70,7 @@ void shouldAssignUnequalDescriptionsToDifferentStepsInAScenarioOutline() { WithStepDescriptions runner = (WithStepDescriptions) PickleRunners.withStepDescriptions( mock(RunnerSupplier.class), features.getPickles().get(0), + null, createJunitOptions()); Description runnerDescription = runner.getDescription(); @@ -93,6 +95,7 @@ void shouldIncludeScenarioNameAsClassNameInStepDescriptions() { PickleRunner runner = PickleRunners.withStepDescriptions( mock(RunnerSupplier.class), features.getPickles().get(0), + null, createJunitOptions()); // fish out the data from runner @@ -115,6 +118,7 @@ void shouldUseScenarioNameForDisplayName() { PickleRunner runner = PickleRunners.withStepDescriptions( mock(RunnerSupplier.class), pickles.get(0), + null, createJunitOptions()); assertEquals("scenario name", runner.getDescription().getDisplayName()); @@ -130,6 +134,7 @@ void shouldUseStepKeyworkAndNameForChildName() { PickleRunner runner = PickleRunners.withStepDescriptions( mock(RunnerSupplier.class), pickles.get(0), + null, createJunitOptions()); assertEquals("it works", runner.getDescription().getChildren().get(0).getMethodName()); @@ -145,6 +150,7 @@ void shouldConvertTextFromFeatureFileForNamesWithFilenameCompatibleNameOption() PickleRunner runner = PickleRunners.withStepDescriptions( mock(RunnerSupplier.class), pickles.get(0), + null, createFileNameCompatibleJunitOptions()); assertEquals("scenario_name", runner.getDescription().getDisplayName()); diff --git a/junit/src/test/resources/io/cucumber/junit/single-duplicate.feature b/junit/src/test/resources/io/cucumber/junit/single-duplicate.feature new file mode 100644 index 0000000000..23641dfe27 --- /dev/null +++ b/junit/src/test/resources/io/cucumber/junit/single-duplicate.feature @@ -0,0 +1,6 @@ +Feature: A feature with a single scenario + + Scenario: A single scenario + Given a single scenario + When it is executed + Then nothing else happens diff --git a/testng/src/test/java/io/cucumber/testng/StubBackendProviderService.java b/testng/src/test/java/io/cucumber/testng/StubBackendProviderService.java index 550055a25a..0b00edb8aa 100644 --- a/testng/src/test/java/io/cucumber/testng/StubBackendProviderService.java +++ b/testng/src/test/java/io/cucumber/testng/StubBackendProviderService.java @@ -35,6 +35,14 @@ private static class StubBackend implements Backend { @Override public void loadGlue(Glue glue, List gluePaths) { + glue.addStepDefinition(createStepDefinition("a scenario")); + glue.addStepDefinition(createStepDefinition("a scenario outline")); + glue.addStepDefinition(createStepDefinition("it is executed")); + glue.addStepDefinition(createStepDefinition("is only runs once")); + glue.addStepDefinition(createStepDefinition("A is used")); + glue.addStepDefinition(createStepDefinition("B is used")); + glue.addStepDefinition(createStepDefinition("C is used")); + glue.addStepDefinition(createStepDefinition("D is used")); glue.addStepDefinition(createStepDefinition("step")); glue.addStepDefinition(createStepDefinition("another step")); glue.addStepDefinition(createStepDefinition("foo")); diff --git a/testng/src/test/resources/io/cucumber/testng/feature-with-outline.feature b/testng/src/test/resources/io/cucumber/testng/feature-with-outline.feature new file mode 100644 index 0000000000..84bc701ac2 --- /dev/null +++ b/testng/src/test/resources/io/cucumber/testng/feature-with-outline.feature @@ -0,0 +1,38 @@ +@FeatureTag +Feature: A feature with scenario outlines + + @ScenarioTag @ResourceA @ResourceAReadOnly + Scenario: A scenario + Given a scenario + When it is executed + Then is only runs once + + @ScenarioOutlineTag + Scenario Outline: A scenario outline + Given a scenario outline + When it is executed + Then is used + + @Example1Tag + Examples: With some text + | example | + | A | + | B | + + @Example2Tag + Examples: With some other text + | example | + | C | + | D | + + @ScenarioOutlineTag + Scenario Outline: A scenario outline with one example + Given a scenario outline + When it is executed + Then is used + + @Example1Tag + Examples: + | example | + | A | + | B |