From d59bf1291356370d4129a254483483ea0c7f1c2e Mon Sep 17 00:00:00 2001 From: andryutz10 Date: Sun, 23 Feb 2014 03:12:05 +0000 Subject: [PATCH 1/2] Add new hooks for global level (BeforeTests and AfterTests) that run only once before all and after all existing features/scenarios, and new hooks for feature level (BeforeFeature and AfterFeature) that run only one before and after a feature(all scenarios in a feature file). Unit test and cucumber test to cover the new hooks and the running order between hooks. --- core/src/main/java/cucumber/runtime/Glue.java | 17 ++- .../java/cucumber/runtime/HookComparator.java | 6 +- .../main/java/cucumber/runtime/Runtime.java | 40 ++++- .../java/cucumber/runtime/RuntimeGlue.java | 60 +++++++- .../java/cucumber/api/java/AfterFeature.java | 26 ++++ .../java/cucumber/api/java/AfterTests.java | 22 +++ .../java/cucumber/api/java/BeforeFeature.java | 26 ++++ .../java/cucumber/api/java/BeforeTests.java | 21 +++ .../java/cucumber/runtime/java/HookType.java | 33 +++++ .../cucumber/runtime/java/JavaBackend.java | 70 ++++++++- .../cucumber/runtime/java/MethodScanner.java | 7 +- .../runtime/java/JavaBackendTest.java | 40 +++++ .../runtime/java/MethodScannerTest.java | 56 ++++++- .../runtime/java/hooks/HooksStepDefs.java | 138 ++++++++++++++++++ .../runtime/java/hooks/HttpServerStub.java | 61 ++++++++ .../java/hooks/RunWithAllHooksTest.java | 9 ++ .../runtime/java/hooks/feature-1.feature | 11 ++ .../runtime/java/hooks/feature-2.feature | 13 ++ .../java/cucumber/api/junit/Cucumber.java | 2 + .../cucumber/runtime/junit/FeatureRunner.java | 6 + .../cucumber/runtime/junit/CucumberTest.java | 22 +++ .../runtime/junit/FeatureRunnerTest.java | 51 +++++++ 22 files changed, 703 insertions(+), 34 deletions(-) create mode 100644 java/src/main/java/cucumber/api/java/AfterFeature.java create mode 100644 java/src/main/java/cucumber/api/java/AfterTests.java create mode 100644 java/src/main/java/cucumber/api/java/BeforeFeature.java create mode 100644 java/src/main/java/cucumber/api/java/BeforeTests.java create mode 100644 java/src/main/java/cucumber/runtime/java/HookType.java create mode 100644 java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java create mode 100644 java/src/test/java/cucumber/runtime/java/hooks/HttpServerStub.java create mode 100644 java/src/test/java/cucumber/runtime/java/hooks/RunWithAllHooksTest.java create mode 100644 java/src/test/resources/cucumber/runtime/java/hooks/feature-1.feature create mode 100644 java/src/test/resources/cucumber/runtime/java/hooks/feature-2.feature create mode 100644 junit/src/test/java/cucumber/runtime/junit/FeatureRunnerTest.java diff --git a/core/src/main/java/cucumber/runtime/Glue.java b/core/src/main/java/cucumber/runtime/Glue.java index 1792a98ea0..bc4da104e0 100644 --- a/core/src/main/java/cucumber/runtime/Glue.java +++ b/core/src/main/java/cucumber/runtime/Glue.java @@ -4,7 +4,6 @@ import gherkin.I18n; import gherkin.formatter.model.Step; -import java.io.IOException; import java.net.URL; import java.util.List; @@ -15,14 +14,30 @@ public interface Glue { void addStepDefinition(StepDefinition stepDefinition) throws DuplicateStepDefinitionException; + void addBeforeTestsHook(HookDefinition hookDefinition); + + void addBeforeFeatureHook(HookDefinition hookDefinition); + void addBeforeHook(HookDefinition hookDefinition); void addAfterHook(HookDefinition hookDefinition); + void addAfterFeatureHook(HookDefinition hookDefinition); + + void addAfterTestsHook(HookDefinition hookDefinition); + + List getBeforeTestsHooks(); + + List getBeforeFeatureHooks(); + List getBeforeHooks(); List getAfterHooks(); + List getAfterFeatureHooks(); + + List getAfterTestsHooks(); + StepDefinitionMatch stepDefinitionMatch(String featurePath, Step step, I18n i18n); void writeStepdefsJson(ResourceLoader resourceLoader, List featurePaths, URL dotCucumber); diff --git a/core/src/main/java/cucumber/runtime/HookComparator.java b/core/src/main/java/cucumber/runtime/HookComparator.java index 2b0f4a04d2..292396c3bb 100644 --- a/core/src/main/java/cucumber/runtime/HookComparator.java +++ b/core/src/main/java/cucumber/runtime/HookComparator.java @@ -5,7 +5,7 @@ class HookComparator implements Comparator { private final boolean ascending; - public HookComparator(boolean ascending) { + private HookComparator(boolean ascending) { this.ascending = ascending; } @@ -14,4 +14,8 @@ public int compare(HookDefinition hook1, HookDefinition hook2) { int comparison = hook1.getOrder() - hook2.getOrder(); return ascending ? comparison : -comparison; } + + // stateless objects - no need for other instances created + public static final HookComparator ASCENDING = new HookComparator(true); + public static final HookComparator DESCENDING = new HookComparator(false); } diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index e4bc9d8973..abb802d210 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.HashSet; /** * This is the main entry point for running Cucumber features. @@ -103,19 +104,24 @@ public void addError(Throwable error) { * This is the main entry point. Used from CLI, but not from JUnit. */ public void run() throws IOException { + Reporter reporter = runtimeOptions.reporter(classLoader); + runBeforeTestsHooks(reporter); for (CucumberFeature cucumberFeature : runtimeOptions.cucumberFeatures(resourceLoader)) { - run(cucumberFeature); + Set tags = new HashSet(cucumberFeature.getGherkinFeature().getTags()); + runBeforeFeatureHooks(reporter, tags); + run(cucumberFeature, reporter); + runAfterFeatureHooks(reporter, tags); } - Formatter formatter = runtimeOptions.formatter(classLoader); + runAfterTestsHooks(reporter); + Formatter formatter = runtimeOptions.formatter(classLoader); formatter.done(); formatter.close(); printSummary(); } - private void run(CucumberFeature cucumberFeature) { + private void run(CucumberFeature cucumberFeature, Reporter reporter) { Formatter formatter = runtimeOptions.formatter(classLoader); - Reporter reporter = runtimeOptions.reporter(classLoader); cucumberFeature.run(formatter, reporter, this); } @@ -203,6 +209,22 @@ public void runAfterHooks(Reporter reporter, Set tags) { runHooks(glue.getAfterHooks(), reporter, tags, false); } + public void runBeforeFeatureHooks(Reporter reporter, Set tags) { + runHooks(glue.getBeforeFeatureHooks(), reporter, tags, true); + } + + public void runAfterFeatureHooks(Reporter reporter, Set tags) { + runHooks(glue.getAfterFeatureHooks(), reporter, tags, false); + } + + public void runBeforeTestsHooks(Reporter reporter) { + runHooks(glue.getBeforeTestsHooks(), reporter, Collections.emptySet(), true); + } + + public void runAfterTestsHooks(Reporter reporter) { + runHooks(glue.getAfterTestsHooks(), reporter, Collections.emptySet(), false); + } + private void runHooks(List hooks, Reporter reporter, Set tags, boolean isBefore) { if (!runtimeOptions.isDryRun()) { for (HookDefinition hook : hooks) { @@ -317,12 +339,18 @@ public static boolean isPending(Throwable t) { } private void addStepToCounterAndResult(Result result) { - scenarioResult.add(result); + // global hooks (@PreTests, @PostTests, @BeforeFeature and @AfterFeature) are not part af a scenario + // so in those cases will be no scenarioResult + if (scenarioResult != null) + scenarioResult.add(result); stats.addStep(result); } private void addHookToCounterAndResult(Result result) { - scenarioResult.add(result); + // global hooks (@PreTests, @PostTests, @BeforeFeature and @AfterFeature) are not part af a scenario + // so in those cases will be no scenarioResult + if (scenarioResult != null) + scenarioResult.add(result); stats.addHookTime(result.getDuration()); } } diff --git a/core/src/main/java/cucumber/runtime/RuntimeGlue.java b/core/src/main/java/cucumber/runtime/RuntimeGlue.java index ea733272c0..67178b9d22 100644 --- a/core/src/main/java/cucumber/runtime/RuntimeGlue.java +++ b/core/src/main/java/cucumber/runtime/RuntimeGlue.java @@ -17,20 +17,26 @@ import java.io.Writer; import java.net.URL; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeMap; +import static cucumber.runtime.HookComparator.ASCENDING; +import static cucumber.runtime.HookComparator.DESCENDING; import static cucumber.runtime.model.CucumberFeature.load; import static java.util.Collections.emptyList; +import static java.util.Collections.sort; public class RuntimeGlue implements Glue { private static final List NO_FILTERS = emptyList(); private final Map stepDefinitionsByPattern = new TreeMap(); + private final List beforeTestsHooks = new ArrayList(); + private final List beforeFeatureHooks = new ArrayList(); private final List beforeHooks = new ArrayList(); private final List afterHooks = new ArrayList(); + private final List afterFeatureHooks = new ArrayList(); + private final List afterTestsHooks = new ArrayList(); private final UndefinedStepsTracker tracker; private final LocalizedXStreams localizedXStreams; @@ -49,16 +55,50 @@ public void addStepDefinition(StepDefinition stepDefinition) { stepDefinitionsByPattern.put(stepDefinition.getPattern(), stepDefinition); } + @Override + public void addBeforeTestsHook(HookDefinition hookDefinition) { + addNewHookAndSort(beforeTestsHooks, hookDefinition, true); + } + + @Override + public void addBeforeFeatureHook(HookDefinition hookDefinition) { + addNewHookAndSort(beforeFeatureHooks, hookDefinition, true); + } + @Override public void addBeforeHook(HookDefinition hookDefinition) { - beforeHooks.add(hookDefinition); - Collections.sort(beforeHooks, new HookComparator(true)); + addNewHookAndSort(beforeHooks, hookDefinition, true); } @Override public void addAfterHook(HookDefinition hookDefinition) { - afterHooks.add(hookDefinition); - Collections.sort(afterHooks, new HookComparator(false)); + addNewHookAndSort(afterHooks, hookDefinition, false); + } + + @Override + public void addAfterFeatureHook(HookDefinition hookDefinition) { + addNewHookAndSort(afterFeatureHooks, hookDefinition, false); + } + + @Override + public void addAfterTestsHook(HookDefinition hookDefinition) { + addNewHookAndSort(afterTestsHooks, hookDefinition, false); + } + + private void addNewHookAndSort(List hooks, HookDefinition hookToAdd, boolean ascending) { + hooks.add(hookToAdd); + if (ascending) sort(hooks, ASCENDING); + else sort(hooks, DESCENDING); + } + + @Override + public List getBeforeTestsHooks() { + return beforeTestsHooks; + } + + @Override + public List getBeforeFeatureHooks() { + return beforeFeatureHooks; } @Override @@ -71,6 +111,16 @@ public List getAfterHooks() { return afterHooks; } + @Override + public List getAfterFeatureHooks() { + return afterFeatureHooks; + } + + @Override + public List getAfterTestsHooks() { + return afterTestsHooks; + } + @Override public StepDefinitionMatch stepDefinitionMatch(String featurePath, Step step, I18n i18n) { List matches = stepDefinitionMatches(featurePath, step); diff --git a/java/src/main/java/cucumber/api/java/AfterFeature.java b/java/src/main/java/cucumber/api/java/AfterFeature.java new file mode 100644 index 0000000000..6fea201f5a --- /dev/null +++ b/java/src/main/java/cucumber/api/java/AfterFeature.java @@ -0,0 +1,26 @@ +package cucumber.api.java; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterFeature { + /** + * @return a tag expression + */ + String[] value() default {}; + + /** + * @return max amount of milliseconds this is allowed to run for. 0 (default) means no restriction. + */ + long timeout() default 0; + + /** + * The order in which this hook should run. Higher numbers are run first. + * The default order is 10000. + */ + int order() default 10000; +} diff --git a/java/src/main/java/cucumber/api/java/AfterTests.java b/java/src/main/java/cucumber/api/java/AfterTests.java new file mode 100644 index 0000000000..e4ceb306eb --- /dev/null +++ b/java/src/main/java/cucumber/api/java/AfterTests.java @@ -0,0 +1,22 @@ +package cucumber.api.java; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterTests { + + /** + * @return max amount of milliseconds this is allowed to run for. 0 (default) means no restriction. + */ + long timeout() default 0; + + /** + * The order in which this hook should run. Higher numbers are run first. + * The default order is 10000. + */ + int order() default Integer.MAX_VALUE; +} diff --git a/java/src/main/java/cucumber/api/java/BeforeFeature.java b/java/src/main/java/cucumber/api/java/BeforeFeature.java new file mode 100644 index 0000000000..9b4fbe58fe --- /dev/null +++ b/java/src/main/java/cucumber/api/java/BeforeFeature.java @@ -0,0 +1,26 @@ +package cucumber.api.java; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BeforeFeature { + /** + * @return a tag expression + */ + String[] value() default {}; + + /** + * @return max amount of milliseconds this is allowed to run for. 0 (default) means no restriction. + */ + long timeout() default 0; + + /** + * The order in which this hook should run. Lower numbers are run first. + * The default order is 10000. + */ + int order() default 10000; +} diff --git a/java/src/main/java/cucumber/api/java/BeforeTests.java b/java/src/main/java/cucumber/api/java/BeforeTests.java new file mode 100644 index 0000000000..38c7164fda --- /dev/null +++ b/java/src/main/java/cucumber/api/java/BeforeTests.java @@ -0,0 +1,21 @@ +package cucumber.api.java; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BeforeTests { + /** + * @return max amount of milliseconds this is allowed to run for. 0 (default) means no restriction. + */ + long timeout() default 0; + + /** + * The order in which this hook should run. Lower numbers are run first. + * The default order is 10000. + */ + int order() default Integer.MIN_VALUE; +} diff --git a/java/src/main/java/cucumber/runtime/java/HookType.java b/java/src/main/java/cucumber/runtime/java/HookType.java new file mode 100644 index 0000000000..8c81e13939 --- /dev/null +++ b/java/src/main/java/cucumber/runtime/java/HookType.java @@ -0,0 +1,33 @@ +package cucumber.runtime.java; + +import cucumber.api.java.*; + +import java.lang.annotation.Annotation; + +enum HookType { + BEFORE_TESTS(BeforeTests.class), + AFTER_TESTS(AfterTests.class), + + BEFORE_FEATURE(BeforeFeature.class), + AFTER_FEATURE(AfterFeature.class), + + BEFORE(Before.class), + AFTER(After.class); + + private Class type; + + private HookType(Class type) { + this.type = type; + } + + private Class getType() { + return type; + } + + public static HookType fromAnnotation(Annotation annotation) { + for (HookType hookType : values()) + if (hookType.type.equals(annotation.annotationType())) return hookType; + + return null; + } +} \ No newline at end of file diff --git a/java/src/main/java/cucumber/runtime/java/JavaBackend.java b/java/src/main/java/cucumber/runtime/java/JavaBackend.java index e93003f546..14babb618c 100644 --- a/java/src/main/java/cucumber/runtime/java/JavaBackend.java +++ b/java/src/main/java/cucumber/runtime/java/JavaBackend.java @@ -2,6 +2,10 @@ import cucumber.api.java.After; import cucumber.api.java.Before; +import cucumber.api.java.AfterFeature; +import cucumber.api.java.BeforeFeature; +import cucumber.api.java.AfterTests; +import cucumber.api.java.BeforeTests; import cucumber.runtime.Backend; import cucumber.runtime.ClassFinder; import cucumber.runtime.CucumberException; @@ -136,17 +140,50 @@ private long timeoutMillis(Annotation annotation) throws Throwable { void addHook(Annotation annotation, Method method) { objectFactory.addClass(method.getDeclaringClass()); - if (annotation.annotationType().equals(Before.class)) { - String[] tagExpressions = ((Before) annotation).value(); - long timeout = ((Before) annotation).timeout(); - glue.addBeforeHook(new JavaHookDefinition(method, tagExpressions, ((Before) annotation).order(), timeout, objectFactory)); - } else { - String[] tagExpressions = ((After) annotation).value(); - long timeout = ((After) annotation).timeout(); - glue.addAfterHook(new JavaHookDefinition(method, tagExpressions, ((After) annotation).order(), timeout, objectFactory)); + HookType hookType = HookType.fromAnnotation(annotation); + HookOptions hookOptions; + switch (hookType) { + case BEFORE_TESTS: + BeforeTests beforeTestsHook = (BeforeTests) annotation; + hookOptions = new HookOptions(beforeTestsHook.order(), beforeTestsHook.timeout()); + glue.addBeforeTestsHook(createJavaHook(hookOptions, method)); + break; + case AFTER_TESTS: + AfterTests afterTestsHook = (AfterTests) annotation; + hookOptions = new HookOptions(afterTestsHook.order(), afterTestsHook.timeout()); + glue.addAfterTestsHook(createJavaHook(hookOptions, method)); + break; + case BEFORE_FEATURE: + BeforeFeature beforeFeatureHook = (BeforeFeature) annotation; + hookOptions = new HookOptions(beforeFeatureHook.order(), beforeFeatureHook.value(), beforeFeatureHook.timeout()); + glue.addBeforeFeatureHook(createJavaHook(hookOptions, method)); + break; + case AFTER_FEATURE: + AfterFeature afterFeatureHook = (AfterFeature) annotation; + hookOptions = new HookOptions(afterFeatureHook.order(), afterFeatureHook.value(), afterFeatureHook.timeout()); + glue.addAfterFeatureHook(createJavaHook(hookOptions, method)); + break; + case BEFORE: + Before beforeHook = (Before) annotation; + hookOptions = new HookOptions(beforeHook.order(), beforeHook.value(), beforeHook.timeout()); + glue.addBeforeHook(createJavaHook(hookOptions, method)); + break; + case AFTER: + After afterHook = (After) annotation; + hookOptions = new HookOptions(afterHook.order(), afterHook.value(), afterHook.timeout()); + glue.addAfterHook(createJavaHook(hookOptions, method)); + break; + default: throw new IllegalArgumentException("Unknown hook type" + hookType); } } + private JavaHookDefinition createJavaHook(HookOptions hookOptions, Method method) { + String[] tagExpressions = hookOptions.tags; + long timeout = hookOptions.timeout; + int order = hookOptions.order; + return new JavaHookDefinition(method, tagExpressions, order, timeout, objectFactory); + } + private static String getMultipleObjectFactoryLogMessage() { StringBuilder sb = new StringBuilder(); sb.append("More than one Cucumber ObjectFactory was found in the classpath\n\n"); @@ -156,4 +193,21 @@ private static String getMultipleObjectFactoryLogMessage() { sb.append("In order to enjoy IoC features, please remove the unnecessary dependencies from your classpath.\n"); return sb.toString(); } + + private static class HookOptions { + String[] tags = {}; + int order; + long timeout; + + private HookOptions(int order, String[] tags, long timeout) { + this.order = order; + this.tags = tags; + this.timeout = timeout; + } + + private HookOptions(int order, long timeout) { + this.order = order; + this.timeout = timeout; + } + } } diff --git a/java/src/main/java/cucumber/runtime/java/MethodScanner.java b/java/src/main/java/cucumber/runtime/java/MethodScanner.java index d97b56a65b..fa5d29d229 100644 --- a/java/src/main/java/cucumber/runtime/java/MethodScanner.java +++ b/java/src/main/java/cucumber/runtime/java/MethodScanner.java @@ -1,10 +1,8 @@ package cucumber.runtime.java; -import cucumber.api.java.After; -import cucumber.api.java.Before; +import cucumber.runtime.ClassFinder; import cucumber.runtime.CucumberException; import cucumber.runtime.Utils; -import cucumber.runtime.ClassFinder; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -76,8 +74,7 @@ private Collection> findCucumberAnnotationClasses() } private boolean isHookAnnotation(Annotation annotation) { - Class annotationClass = annotation.annotationType(); - return annotationClass.equals(Before.class) || annotationClass.equals(After.class); + return HookType.fromAnnotation(annotation) != null; } private boolean isStepdefAnnotation(Annotation annotation) { diff --git a/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java b/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java index 7a54aee7d5..9101b7a6f3 100644 --- a/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java +++ b/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java @@ -55,6 +55,16 @@ public void addStepDefinition(StepDefinition stepDefinition) { stepDefinitions.add(stepDefinition); } + @Override + public void addBeforeTestsHook(HookDefinition hookDefinition) { + throw new UnsupportedOperationException(); + } + + @Override + public void addBeforeFeatureHook(HookDefinition hookDefinition) { + throw new UnsupportedOperationException(); + } + @Override public void addBeforeHook(HookDefinition hookDefinition) { throw new UnsupportedOperationException(); @@ -65,6 +75,26 @@ public void addAfterHook(HookDefinition hookDefinition) { throw new UnsupportedOperationException(); } + @Override + public void addAfterFeatureHook(HookDefinition hookDefinition) { + throw new UnsupportedOperationException(); + } + + @Override + public void addAfterTestsHook(HookDefinition hookDefinition) { + throw new UnsupportedOperationException(); + } + + @Override + public List getBeforeTestsHooks() { + throw new UnsupportedOperationException(); + } + + @Override + public List getBeforeFeatureHooks() { + throw new UnsupportedOperationException(); + } + @Override public List getBeforeHooks() { throw new UnsupportedOperationException(); @@ -75,6 +105,16 @@ public List getAfterHooks() { throw new UnsupportedOperationException(); } + @Override + public List getAfterFeatureHooks() { + throw new UnsupportedOperationException(); + } + + @Override + public List getAfterTestsHooks() { + throw new UnsupportedOperationException(); + } + @Override public StepDefinitionMatch stepDefinitionMatch(String featurePath, Step step, I18n i18n) { throw new UnsupportedOperationException(); diff --git a/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java b/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java index b4506fe739..a097fd59a1 100644 --- a/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java +++ b/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java @@ -1,6 +1,11 @@ package cucumber.runtime.java; import cucumber.api.java.Before; +import cucumber.api.java.After; +import cucumber.api.java.BeforeFeature; +import cucumber.api.java.AfterFeature; +import cucumber.api.java.BeforeTests; +import cucumber.api.java.AfterTests; import cucumber.runtime.CucumberException; import cucumber.runtime.Glue; import cucumber.runtime.io.MultiLoader; @@ -12,7 +17,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.any; public class MethodScannerTest { @@ -23,22 +32,33 @@ public void loadGlue_registers_the_methods_declaring_class_in_the_object_factory MethodScanner methodScanner = new MethodScanner(new ResourceLoaderClassFinder(resourceLoader, classLoader)); ObjectFactory factory = Mockito.mock(ObjectFactory.class); - Glue world = Mockito.mock(Glue.class); + Glue world = mock(Glue.class); JavaBackend backend = new JavaBackend(factory); Whitebox.setInternalState(backend, "glue", world); // this delegates to methodScanner.scan which we test - methodScanner.scan(backend, BaseStepDefs.class.getMethod("m"), BaseStepDefs.class); + methodScanner.scan(backend, BaseStepDefs.class.getMethod("m0"), BaseStepDefs.class); + methodScanner.scan(backend, BaseStepDefs.class.getMethod("m1"), BaseStepDefs.class); + methodScanner.scan(backend, BaseStepDefs.class.getMethod("m2"), BaseStepDefs.class); + methodScanner.scan(backend, BaseStepDefs.class.getMethod("m3"), BaseStepDefs.class); + methodScanner.scan(backend, BaseStepDefs.class.getMethod("m4"), BaseStepDefs.class); + methodScanner.scan(backend, BaseStepDefs.class.getMethod("m5"), BaseStepDefs.class); - verify(factory, times(1)).addClass(BaseStepDefs.class); - verifyNoMoreInteractions(factory); + verify(world, times(1)).addBeforeTestsHook(any(JavaHookDefinition.class)); + verify(world, times(1)).addBeforeFeatureHook(any(JavaHookDefinition.class)); + verify(world, times(1)).addBeforeHook(any(JavaHookDefinition.class)); + verify(world, times(1)).addAfterHook(any(JavaHookDefinition.class)); + verify(world, times(1)).addAfterFeatureHook(any(JavaHookDefinition.class)); + verify(world, times(1)).addAfterTestsHook(any(JavaHookDefinition.class)); + verify(factory, times(6)).addClass(BaseStepDefs.class); + verifyNoMoreInteractions(factory, world); } @Test public void loadGlue_fails_when_class_is_not_method_declaring_class() throws NoSuchMethodException { JavaBackend backend = new JavaBackend((ObjectFactory) null); try { - backend.loadGlue(null, BaseStepDefs.class.getMethod("m"), Stepdefs2.class); + backend.loadGlue(null, BaseStepDefs.class.getMethod("m0"), Stepdefs2.class); fail(); } catch (CucumberException e) { assertEquals("You're not allowed to extend classes that define Step Definitions or hooks. class cucumber.runtime.java.MethodScannerTest$Stepdefs2 extends class cucumber.runtime.java.MethodScannerTest$BaseStepDefs", e.getMessage()); @@ -49,7 +69,7 @@ public void loadGlue_fails_when_class_is_not_method_declaring_class() throws NoS public void loadGlue_fails_when_class_is_not_subclass_of_declaring_class() throws NoSuchMethodException { JavaBackend backend = new JavaBackend((ObjectFactory) null); try { - backend.loadGlue(null, BaseStepDefs.class.getMethod("m"), String.class); + backend.loadGlue(null, BaseStepDefs.class.getMethod("m0"), String.class); fail(); } catch (CucumberException e) { assertEquals("class cucumber.runtime.java.MethodScannerTest$BaseStepDefs isn't assignable from class java.lang.String", e.getMessage()); @@ -62,8 +82,28 @@ public interface Interface1 { } public static class BaseStepDefs { + @BeforeTests + public void m0(){ + } + @Before - public void m() { + public void m1() { + } + + @BeforeFeature + public void m2() { + } + + @After + public void m3() { + } + + @AfterFeature + public void m4() { + } + + @AfterTests + public void m5() { } } } diff --git a/java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java b/java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java new file mode 100644 index 0000000000..033314008b --- /dev/null +++ b/java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java @@ -0,0 +1,138 @@ +package cucumber.runtime.java.hooks; + +import cucumber.api.java.*; +import cucumber.api.java.en.Given; +import cucumber.api.java.en.Then; +import cucumber.api.java.en.When; +import cucumber.runtime.java.StepDefAnnotation; + +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.assertThat; + +@StepDefAnnotation +public class HooksStepDefs { + + private static HttpServerStub httpServer = new HttpServerStub(); + private HttpServerStub.Request simpleRequest = new HttpServerStub.Request("data to save"); + private int responseCode = 0; + private String data; + private String dataToRestore; + private static List hooksOrder = new ArrayList(); + static { + // hooks order for two feature files, each with 2 scenarios, + // the second feature has tags for custom feature hooks - BeforeFeature(@...) and AfterFeature(@...) + + // global hook before tests + hooksOrder.add("@BeforeTests"); + + // first feature expected hooks in order + hooksOrder.add("@BeforeFeature(order = 10)"); + hooksOrder.add("@Before"); + hooksOrder.add("@After"); + hooksOrder.add("@Before"); + hooksOrder.add("@After"); + hooksOrder.add("@AfterFeature(order = 10)"); + + // second feature expected hooks in order + hooksOrder.add("@BeforeFeature(order = 10)"); + hooksOrder.add("@BeforeFeature(@CleanServerData)"); + hooksOrder.add("@Before"); + hooksOrder.add("@After"); + hooksOrder.add("@Before"); + hooksOrder.add("@After"); + hooksOrder.add("@AfterFeature(@RestoreServerData)"); + hooksOrder.add("@AfterFeature(order = 10)"); + + // global hook after tests + hooksOrder.add("@AfterTests"); + } + + @BeforeTests + public void startServer() { + ensureHooksOrder("@BeforeTests"); + httpServer = new HttpServerStub(); + httpServer.start(); + assertThat("The server should be started", httpServer.isStarted(), is(true)); + } + + @AfterTests + public void stopServer() { + ensureHooksOrder("@AfterTests"); + assertThat("The server should be started",httpServer.isStarted(), is(true)); + httpServer.stop(); + assertThat("The server should be stopped",httpServer.isStarted(), is(false)); + } + + @BeforeFeature("@CleanServerData") + public void cleanServerData(){ + ensureHooksOrder("@BeforeFeature(@CleanServerData)"); + assertThat(httpServer.receive(), is(notNullValue())); + dataToRestore = httpServer.receive(); + httpServer.clean(); + } + + @AfterFeature("@RestoreServerData") + public void restoreServerData(){ + ensureHooksOrder("@AfterFeature(@RestoreServerData)"); + assertThat(httpServer.receive(), is(notNullValue())); + httpServer.send(new HttpServerStub.Request(dataToRestore)); + } + + @BeforeFeature(order = 10) + public void beforeFeature(){ + ensureHooksOrder("@BeforeFeature(order = 10)"); + } + + @AfterFeature(order = 10) + public void afterFeature(){ + ensureHooksOrder("@AfterFeature(order = 10)"); + } + + @Before + public void beforeScenario() { + ensureHooksOrder("@Before"); + } + + @After + public void afterScenario() { + ensureHooksOrder("@After"); + } + + @Given("^that we have a http server up and running and no data on it$") + public void that_we_have_a_http_server_up_and_running_and_no_data_on_it() throws Throwable { + assertThat(httpServer.receive(), is(nullValue())); + } + + @Given("^that we have a http server up and running$") + public void a_up_and_running_http_server() throws Throwable { + assertThat("The server should be started",httpServer.isStarted(), is(true)); + } + + @When("^I send a request to save some data$") + public void I_send_a_request_to_save_some_data() { + responseCode = httpServer.send(simpleRequest); + } + + @When("^I send a request to get the existing data on http server$") + public void i_send_a_request_to_get_the_existing_data_on_http_server() throws Throwable { + data = httpServer.receive(); + } + + @Then("^I expect a success response code of (\\d+)$") + public void I_expect_a_success_response_code_of(int code) { + assertThat("Unexpected response code. expected: " + code + " actual: " + responseCode, responseCode, is(code)); + } + + @Then("^I expect to get back some data$") + public void I_expect_to_get_back_some_data() throws Throwable { + assertThat(data, is(simpleRequest.getData())); + } + + private void ensureHooksOrder(String currentHook) { + String expected = hooksOrder.remove(0); + assertThat(currentHook, is(expected)); + } +} diff --git a/java/src/test/java/cucumber/runtime/java/hooks/HttpServerStub.java b/java/src/test/java/cucumber/runtime/java/hooks/HttpServerStub.java new file mode 100644 index 0000000000..0fd4946741 --- /dev/null +++ b/java/src/test/java/cucumber/runtime/java/hooks/HttpServerStub.java @@ -0,0 +1,61 @@ +package cucumber.runtime.java.hooks; + +public class HttpServerStub { + private boolean isStarted; + private Request request; + + public void start() { + if (isStarted) { + throw new IllegalStateException("Server already started!"); + } + try { + Thread.sleep(2000); + isStarted = true; + } catch (InterruptedException e) {} + } + + public void stop() { + if (!isStarted) { + throw new IllegalStateException("Server is not running!"); + } + try { + Thread.sleep(2000); + isStarted = false; + } catch (InterruptedException e) {} + } + + public boolean isStarted() { + return isStarted; + } + + public int send(Request request) { + if (!isStarted) { + throw new IllegalStateException("server is not running"); + } + this.request = request; + return 200; + } + + public String receive() { + if (!isStarted) { + throw new IllegalStateException("server is not running"); + } + return request.getData(); + } + + public void clean() { + request = new Request(null); + } + + static class Request { + private T data; + + Request(T data) { + this.data = data; + } + + T getData() { + return data; + } + } +} diff --git a/java/src/test/java/cucumber/runtime/java/hooks/RunWithAllHooksTest.java b/java/src/test/java/cucumber/runtime/java/hooks/RunWithAllHooksTest.java new file mode 100644 index 0000000000..5a31eed494 --- /dev/null +++ b/java/src/test/java/cucumber/runtime/java/hooks/RunWithAllHooksTest.java @@ -0,0 +1,9 @@ +package cucumber.runtime.java.hooks; + +import cucumber.api.CucumberOptions; +import cucumber.api.junit.Cucumber; +import org.junit.runner.RunWith; + +@RunWith(Cucumber.class) +public class RunWithAllHooksTest { +} diff --git a/java/src/test/resources/cucumber/runtime/java/hooks/feature-1.feature b/java/src/test/resources/cucumber/runtime/java/hooks/feature-1.feature new file mode 100644 index 0000000000..0cf5cc2a96 --- /dev/null +++ b/java/src/test/resources/cucumber/runtime/java/hooks/feature-1.feature @@ -0,0 +1,11 @@ +Feature: Use global hooks to start a server and send some requests + + Scenario: Send request to a server to save some data and expect a success response code back + Given that we have a http server up and running + When I send a request to save some data + Then I expect a success response code of 200 + + Scenario: Retrieve data saved on the http server + Given that we have a http server up and running + When I send a request to get the existing data on http server + Then I expect to get back some data diff --git a/java/src/test/resources/cucumber/runtime/java/hooks/feature-2.feature b/java/src/test/resources/cucumber/runtime/java/hooks/feature-2.feature new file mode 100644 index 0000000000..9b7d27a44f --- /dev/null +++ b/java/src/test/resources/cucumber/runtime/java/hooks/feature-2.feature @@ -0,0 +1,13 @@ +@CleanServerData +@RestoreServerData +Feature: Use before feature and after feature hooks to save/retrieve data from server + + Scenario: No data on the server but we are gone send some in this scenario + Given that we have a http server up and running and no data on it + When I send a request to save some data + Then I expect a success response code of 200 + + Scenario: Retrieve data saved on the http server + Given that we have a http server up and running + When I send a request to get the existing data on http server + Then I expect to get back some data diff --git a/junit/src/main/java/cucumber/api/junit/Cucumber.java b/junit/src/main/java/cucumber/api/junit/Cucumber.java index 6a978c0334..66a0f2c587 100644 --- a/junit/src/main/java/cucumber/api/junit/Cucumber.java +++ b/junit/src/main/java/cucumber/api/junit/Cucumber.java @@ -83,7 +83,9 @@ protected void runChild(FeatureRunner child, RunNotifier notifier) { @Override public void run(RunNotifier notifier) { + runtime.runBeforeTestsHooks(jUnitReporter); super.run(notifier); + runtime.runAfterTestsHooks(jUnitReporter); jUnitReporter.done(); jUnitReporter.close(); runtime.printSummary(); diff --git a/junit/src/main/java/cucumber/runtime/junit/FeatureRunner.java b/junit/src/main/java/cucumber/runtime/junit/FeatureRunner.java index eb5928ab75..684c834312 100644 --- a/junit/src/main/java/cucumber/runtime/junit/FeatureRunner.java +++ b/junit/src/main/java/cucumber/runtime/junit/FeatureRunner.java @@ -7,13 +7,16 @@ import cucumber.runtime.model.CucumberScenarioOutline; import cucumber.runtime.model.CucumberTagStatement; import gherkin.formatter.model.Feature; +import gherkin.formatter.model.Tag; import org.junit.runner.Description; import org.junit.runner.notification.RunNotifier; import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class FeatureRunner extends ParentRunner { private final List children = new ArrayList(); @@ -67,7 +70,10 @@ protected void runChild(ParentRunner child, RunNotifier notifier) { public void run(RunNotifier notifier) { jUnitReporter.uri(cucumberFeature.getPath()); jUnitReporter.feature(cucumberFeature.getGherkinFeature()); + Set tags = new HashSet(cucumberFeature.getGherkinFeature().getTags()); + runtime.runBeforeFeatureHooks(jUnitReporter, tags); super.run(notifier); + runtime.runAfterFeatureHooks(jUnitReporter, tags); jUnitReporter.eof(); } diff --git a/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java b/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java index 99e82c5008..49cca88458 100644 --- a/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java +++ b/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java @@ -4,11 +4,15 @@ import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; import cucumber.runtime.CucumberException; +import cucumber.runtime.Runtime; +import gherkin.formatter.Reporter; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runner.notification.RunNotifier; import org.junit.runners.model.InitializationError; +import org.mockito.internal.util.reflection.Whitebox; import java.io.File; import java.io.IOException; @@ -17,6 +21,11 @@ import static java.util.Collections.emptyList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; public class CucumberTest { @@ -67,6 +76,19 @@ public void finds_no_features_when_explicit_feature_path_has_no_features() throw assertEquals(emptyList(), children); } + @Test + public void testRun_verify_that_preTests_and_postTests_hooks_are_executed() throws Exception { + Cucumber cucumber = new Cucumber(ImplicitFeatureAndGluePath.class); + Runtime runtime = mock(Runtime.class); + Whitebox.setInternalState(cucumber, "runtime", runtime); + RunNotifier runNotifier = new RunNotifier(); + cucumber.run(runNotifier); + verify(runtime, times(1)).runBeforeTestsHooks(any(Reporter.class)); + verify(runtime, times(1)).runAfterTestsHooks(any(Reporter.class)); + verify(runtime, times(1)).printSummary(); + verifyNoMoreInteractions(runtime); + } + @RunWith(Cucumber.class) private class RunCukesTestValidEmpty { } diff --git a/junit/src/test/java/cucumber/runtime/junit/FeatureRunnerTest.java b/junit/src/test/java/cucumber/runtime/junit/FeatureRunnerTest.java new file mode 100644 index 0000000000..b17a5c9925 --- /dev/null +++ b/junit/src/test/java/cucumber/runtime/junit/FeatureRunnerTest.java @@ -0,0 +1,51 @@ +package cucumber.runtime.junit; + +import cucumber.runtime.Runtime; +import cucumber.runtime.model.CucumberFeature; +import gherkin.formatter.model.Comment; +import gherkin.formatter.model.Feature; +import gherkin.formatter.model.Tag; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.notification.RunNotifier; + +import java.util.Collections; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anySet; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +public class FeatureRunnerTest { + private FeatureRunner featureRunner; + private CucumberFeature cucumberFeature; + private Runtime runtime; + private JUnitReporter jUnitReporter; + private Feature feature = new Feature(Collections.emptyList(), Collections.emptyList(), "keyword", "name", "description", 1, "id"); + + @Before + public void setUp() throws Exception { + cucumberFeature = mock(CucumberFeature.class); + runtime = mock(Runtime.class); + jUnitReporter = mock(JUnitReporter.class); + featureRunner = new FeatureRunner(cucumberFeature, runtime, jUnitReporter); + + } + + @Test + public void testRun() throws Exception { + when(cucumberFeature.getGherkinFeature()).thenReturn(feature); + when(cucumberFeature.getPath()).thenReturn("path"); + + featureRunner.run(new RunNotifier()); + + verify(cucumberFeature, times(4)).getGherkinFeature(); + verify(cucumberFeature, times(1)).getPath(); + verify(jUnitReporter, times(1)).uri(anyString()); + verify(jUnitReporter, times(1)).feature(any(Feature.class)); + verify(runtime, times(1)).runBeforeFeatureHooks(any(JUnitReporter.class), anySet()); + verify(runtime, times(1)).runAfterFeatureHooks(any(JUnitReporter.class), anySet()); + verify(jUnitReporter, times(1)).eof(); + verifyNoMoreInteractions(runtime, jUnitReporter); + } +} From 2e38c8820ed490379888da8226b2fbf350c02271 Mon Sep 17 00:00:00 2001 From: andryutz10 Date: Tue, 25 Feb 2014 19:49:08 +0000 Subject: [PATCH 2/2] Rename BeforeTests and AfterTests with BeforeAll and AfterAll --- core/src/main/java/cucumber/runtime/Glue.java | 8 ++++---- .../main/java/cucumber/runtime/Runtime.java | 16 +++++++-------- .../java/cucumber/runtime/RuntimeGlue.java | 20 +++++++++---------- .../java/{AfterTests.java => AfterAll.java} | 2 +- .../java/{BeforeTests.java => BeforeAll.java} | 2 +- .../java/cucumber/runtime/java/HookType.java | 4 ++-- .../cucumber/runtime/java/JavaBackend.java | 20 +++++++++---------- .../runtime/java/JavaBackendTest.java | 8 ++++---- .../runtime/java/MethodScannerTest.java | 12 +++++------ .../runtime/java/hooks/HooksStepDefs.java | 12 +++++------ .../java/cucumber/api/junit/Cucumber.java | 4 ++-- .../cucumber/runtime/junit/CucumberTest.java | 4 ++-- 12 files changed, 56 insertions(+), 56 deletions(-) rename java/src/main/java/cucumber/api/java/{AfterTests.java => AfterAll.java} (94%) rename java/src/main/java/cucumber/api/java/{BeforeTests.java => BeforeAll.java} (94%) diff --git a/core/src/main/java/cucumber/runtime/Glue.java b/core/src/main/java/cucumber/runtime/Glue.java index bc4da104e0..29415bf0dd 100644 --- a/core/src/main/java/cucumber/runtime/Glue.java +++ b/core/src/main/java/cucumber/runtime/Glue.java @@ -14,7 +14,7 @@ public interface Glue { void addStepDefinition(StepDefinition stepDefinition) throws DuplicateStepDefinitionException; - void addBeforeTestsHook(HookDefinition hookDefinition); + void addBeforeAllHook(HookDefinition hookDefinition); void addBeforeFeatureHook(HookDefinition hookDefinition); @@ -24,9 +24,9 @@ public interface Glue { void addAfterFeatureHook(HookDefinition hookDefinition); - void addAfterTestsHook(HookDefinition hookDefinition); + void addAfterAllHook(HookDefinition hookDefinition); - List getBeforeTestsHooks(); + List getBeforeAllHooks(); List getBeforeFeatureHooks(); @@ -36,7 +36,7 @@ public interface Glue { List getAfterFeatureHooks(); - List getAfterTestsHooks(); + List getAfterAllHooks(); StepDefinitionMatch stepDefinitionMatch(String featurePath, Step step, I18n i18n); diff --git a/core/src/main/java/cucumber/runtime/Runtime.java b/core/src/main/java/cucumber/runtime/Runtime.java index abb802d210..66c50782f3 100644 --- a/core/src/main/java/cucumber/runtime/Runtime.java +++ b/core/src/main/java/cucumber/runtime/Runtime.java @@ -105,14 +105,14 @@ public void addError(Throwable error) { */ public void run() throws IOException { Reporter reporter = runtimeOptions.reporter(classLoader); - runBeforeTestsHooks(reporter); + runBeforeAllHooks(reporter); for (CucumberFeature cucumberFeature : runtimeOptions.cucumberFeatures(resourceLoader)) { Set tags = new HashSet(cucumberFeature.getGherkinFeature().getTags()); runBeforeFeatureHooks(reporter, tags); run(cucumberFeature, reporter); runAfterFeatureHooks(reporter, tags); } - runAfterTestsHooks(reporter); + runAfterAllHooks(reporter); Formatter formatter = runtimeOptions.formatter(classLoader); formatter.done(); @@ -217,12 +217,12 @@ public void runAfterFeatureHooks(Reporter reporter, Set tags) { runHooks(glue.getAfterFeatureHooks(), reporter, tags, false); } - public void runBeforeTestsHooks(Reporter reporter) { - runHooks(glue.getBeforeTestsHooks(), reporter, Collections.emptySet(), true); + public void runBeforeAllHooks(Reporter reporter) { + runHooks(glue.getBeforeAllHooks(), reporter, Collections.emptySet(), true); } - public void runAfterTestsHooks(Reporter reporter) { - runHooks(glue.getAfterTestsHooks(), reporter, Collections.emptySet(), false); + public void runAfterAllHooks(Reporter reporter) { + runHooks(glue.getAfterAllHooks(), reporter, Collections.emptySet(), false); } private void runHooks(List hooks, Reporter reporter, Set tags, boolean isBefore) { @@ -339,7 +339,7 @@ public static boolean isPending(Throwable t) { } private void addStepToCounterAndResult(Result result) { - // global hooks (@PreTests, @PostTests, @BeforeFeature and @AfterFeature) are not part af a scenario + // global hooks (@BeforeAll, @AfterAll, @BeforeFeature and @AfterFeature) are not part af a scenario // so in those cases will be no scenarioResult if (scenarioResult != null) scenarioResult.add(result); @@ -347,7 +347,7 @@ private void addStepToCounterAndResult(Result result) { } private void addHookToCounterAndResult(Result result) { - // global hooks (@PreTests, @PostTests, @BeforeFeature and @AfterFeature) are not part af a scenario + // global hooks (@BeforeAll, @AfterAll, @BeforeFeature and @AfterFeature) are not part af a scenario // so in those cases will be no scenarioResult if (scenarioResult != null) scenarioResult.add(result); diff --git a/core/src/main/java/cucumber/runtime/RuntimeGlue.java b/core/src/main/java/cucumber/runtime/RuntimeGlue.java index 67178b9d22..c624d22b7a 100644 --- a/core/src/main/java/cucumber/runtime/RuntimeGlue.java +++ b/core/src/main/java/cucumber/runtime/RuntimeGlue.java @@ -31,12 +31,12 @@ public class RuntimeGlue implements Glue { private static final List NO_FILTERS = emptyList(); private final Map stepDefinitionsByPattern = new TreeMap(); - private final List beforeTestsHooks = new ArrayList(); + private final List beforeAllHooks = new ArrayList(); private final List beforeFeatureHooks = new ArrayList(); private final List beforeHooks = new ArrayList(); private final List afterHooks = new ArrayList(); private final List afterFeatureHooks = new ArrayList(); - private final List afterTestsHooks = new ArrayList(); + private final List afterAllHooks = new ArrayList(); private final UndefinedStepsTracker tracker; private final LocalizedXStreams localizedXStreams; @@ -56,8 +56,8 @@ public void addStepDefinition(StepDefinition stepDefinition) { } @Override - public void addBeforeTestsHook(HookDefinition hookDefinition) { - addNewHookAndSort(beforeTestsHooks, hookDefinition, true); + public void addBeforeAllHook(HookDefinition hookDefinition) { + addNewHookAndSort(beforeAllHooks, hookDefinition, true); } @Override @@ -81,8 +81,8 @@ public void addAfterFeatureHook(HookDefinition hookDefinition) { } @Override - public void addAfterTestsHook(HookDefinition hookDefinition) { - addNewHookAndSort(afterTestsHooks, hookDefinition, false); + public void addAfterAllHook(HookDefinition hookDefinition) { + addNewHookAndSort(afterAllHooks, hookDefinition, false); } private void addNewHookAndSort(List hooks, HookDefinition hookToAdd, boolean ascending) { @@ -92,8 +92,8 @@ private void addNewHookAndSort(List hooks, HookDefinition hookTo } @Override - public List getBeforeTestsHooks() { - return beforeTestsHooks; + public List getBeforeAllHooks() { + return beforeAllHooks; } @Override @@ -117,8 +117,8 @@ public List getAfterFeatureHooks() { } @Override - public List getAfterTestsHooks() { - return afterTestsHooks; + public List getAfterAllHooks() { + return afterAllHooks; } @Override diff --git a/java/src/main/java/cucumber/api/java/AfterTests.java b/java/src/main/java/cucumber/api/java/AfterAll.java similarity index 94% rename from java/src/main/java/cucumber/api/java/AfterTests.java rename to java/src/main/java/cucumber/api/java/AfterAll.java index e4ceb306eb..066390cce7 100644 --- a/java/src/main/java/cucumber/api/java/AfterTests.java +++ b/java/src/main/java/cucumber/api/java/AfterAll.java @@ -7,7 +7,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface AfterTests { +public @interface AfterAll { /** * @return max amount of milliseconds this is allowed to run for. 0 (default) means no restriction. diff --git a/java/src/main/java/cucumber/api/java/BeforeTests.java b/java/src/main/java/cucumber/api/java/BeforeAll.java similarity index 94% rename from java/src/main/java/cucumber/api/java/BeforeTests.java rename to java/src/main/java/cucumber/api/java/BeforeAll.java index 38c7164fda..bb38266b54 100644 --- a/java/src/main/java/cucumber/api/java/BeforeTests.java +++ b/java/src/main/java/cucumber/api/java/BeforeAll.java @@ -7,7 +7,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface BeforeTests { +public @interface BeforeAll { /** * @return max amount of milliseconds this is allowed to run for. 0 (default) means no restriction. */ diff --git a/java/src/main/java/cucumber/runtime/java/HookType.java b/java/src/main/java/cucumber/runtime/java/HookType.java index 8c81e13939..0255c3243e 100644 --- a/java/src/main/java/cucumber/runtime/java/HookType.java +++ b/java/src/main/java/cucumber/runtime/java/HookType.java @@ -5,8 +5,8 @@ import java.lang.annotation.Annotation; enum HookType { - BEFORE_TESTS(BeforeTests.class), - AFTER_TESTS(AfterTests.class), + BEFORE_ALL(BeforeAll.class), + AFTER_ALL(AfterAll.class), BEFORE_FEATURE(BeforeFeature.class), AFTER_FEATURE(AfterFeature.class), diff --git a/java/src/main/java/cucumber/runtime/java/JavaBackend.java b/java/src/main/java/cucumber/runtime/java/JavaBackend.java index 14babb618c..c1d7552aaa 100644 --- a/java/src/main/java/cucumber/runtime/java/JavaBackend.java +++ b/java/src/main/java/cucumber/runtime/java/JavaBackend.java @@ -4,8 +4,8 @@ import cucumber.api.java.Before; import cucumber.api.java.AfterFeature; import cucumber.api.java.BeforeFeature; -import cucumber.api.java.AfterTests; -import cucumber.api.java.BeforeTests; +import cucumber.api.java.AfterAll; +import cucumber.api.java.BeforeAll; import cucumber.runtime.Backend; import cucumber.runtime.ClassFinder; import cucumber.runtime.CucumberException; @@ -143,15 +143,15 @@ void addHook(Annotation annotation, Method method) { HookType hookType = HookType.fromAnnotation(annotation); HookOptions hookOptions; switch (hookType) { - case BEFORE_TESTS: - BeforeTests beforeTestsHook = (BeforeTests) annotation; - hookOptions = new HookOptions(beforeTestsHook.order(), beforeTestsHook.timeout()); - glue.addBeforeTestsHook(createJavaHook(hookOptions, method)); + case BEFORE_ALL: + BeforeAll beforeAllHook = (BeforeAll) annotation; + hookOptions = new HookOptions(beforeAllHook.order(), beforeAllHook.timeout()); + glue.addBeforeAllHook(createJavaHook(hookOptions, method)); break; - case AFTER_TESTS: - AfterTests afterTestsHook = (AfterTests) annotation; - hookOptions = new HookOptions(afterTestsHook.order(), afterTestsHook.timeout()); - glue.addAfterTestsHook(createJavaHook(hookOptions, method)); + case AFTER_ALL: + AfterAll afterAllHook = (AfterAll) annotation; + hookOptions = new HookOptions(afterAllHook.order(), afterAllHook.timeout()); + glue.addAfterAllHook(createJavaHook(hookOptions, method)); break; case BEFORE_FEATURE: BeforeFeature beforeFeatureHook = (BeforeFeature) annotation; diff --git a/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java b/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java index 9101b7a6f3..540e8f658e 100644 --- a/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java +++ b/java/src/test/java/cucumber/runtime/java/JavaBackendTest.java @@ -56,7 +56,7 @@ public void addStepDefinition(StepDefinition stepDefinition) { } @Override - public void addBeforeTestsHook(HookDefinition hookDefinition) { + public void addBeforeAllHook(HookDefinition hookDefinition) { throw new UnsupportedOperationException(); } @@ -81,12 +81,12 @@ public void addAfterFeatureHook(HookDefinition hookDefinition) { } @Override - public void addAfterTestsHook(HookDefinition hookDefinition) { + public void addAfterAllHook(HookDefinition hookDefinition) { throw new UnsupportedOperationException(); } @Override - public List getBeforeTestsHooks() { + public List getBeforeAllHooks() { throw new UnsupportedOperationException(); } @@ -111,7 +111,7 @@ public List getAfterFeatureHooks() { } @Override - public List getAfterTestsHooks() { + public List getAfterAllHooks() { throw new UnsupportedOperationException(); } diff --git a/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java b/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java index a097fd59a1..4a62558d75 100644 --- a/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java +++ b/java/src/test/java/cucumber/runtime/java/MethodScannerTest.java @@ -4,8 +4,8 @@ import cucumber.api.java.After; import cucumber.api.java.BeforeFeature; import cucumber.api.java.AfterFeature; -import cucumber.api.java.BeforeTests; -import cucumber.api.java.AfterTests; +import cucumber.api.java.BeforeAll; +import cucumber.api.java.AfterAll; import cucumber.runtime.CucumberException; import cucumber.runtime.Glue; import cucumber.runtime.io.MultiLoader; @@ -44,12 +44,12 @@ public void loadGlue_registers_the_methods_declaring_class_in_the_object_factory methodScanner.scan(backend, BaseStepDefs.class.getMethod("m4"), BaseStepDefs.class); methodScanner.scan(backend, BaseStepDefs.class.getMethod("m5"), BaseStepDefs.class); - verify(world, times(1)).addBeforeTestsHook(any(JavaHookDefinition.class)); + verify(world, times(1)).addBeforeAllHook(any(JavaHookDefinition.class)); verify(world, times(1)).addBeforeFeatureHook(any(JavaHookDefinition.class)); verify(world, times(1)).addBeforeHook(any(JavaHookDefinition.class)); verify(world, times(1)).addAfterHook(any(JavaHookDefinition.class)); verify(world, times(1)).addAfterFeatureHook(any(JavaHookDefinition.class)); - verify(world, times(1)).addAfterTestsHook(any(JavaHookDefinition.class)); + verify(world, times(1)).addAfterAllHook(any(JavaHookDefinition.class)); verify(factory, times(6)).addClass(BaseStepDefs.class); verifyNoMoreInteractions(factory, world); } @@ -82,7 +82,7 @@ public interface Interface1 { } public static class BaseStepDefs { - @BeforeTests + @BeforeAll public void m0(){ } @@ -102,7 +102,7 @@ public void m3() { public void m4() { } - @AfterTests + @AfterAll public void m5() { } } diff --git a/java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java b/java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java index 033314008b..23e6c40c40 100644 --- a/java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java +++ b/java/src/test/java/cucumber/runtime/java/hooks/HooksStepDefs.java @@ -26,7 +26,7 @@ public class HooksStepDefs { // the second feature has tags for custom feature hooks - BeforeFeature(@...) and AfterFeature(@...) // global hook before tests - hooksOrder.add("@BeforeTests"); + hooksOrder.add("@BeforeAll"); // first feature expected hooks in order hooksOrder.add("@BeforeFeature(order = 10)"); @@ -47,20 +47,20 @@ public class HooksStepDefs { hooksOrder.add("@AfterFeature(order = 10)"); // global hook after tests - hooksOrder.add("@AfterTests"); + hooksOrder.add("@AfterAll"); } - @BeforeTests + @BeforeAll public void startServer() { - ensureHooksOrder("@BeforeTests"); + ensureHooksOrder("@BeforeAll"); httpServer = new HttpServerStub(); httpServer.start(); assertThat("The server should be started", httpServer.isStarted(), is(true)); } - @AfterTests + @AfterAll public void stopServer() { - ensureHooksOrder("@AfterTests"); + ensureHooksOrder("@AfterAll"); assertThat("The server should be started",httpServer.isStarted(), is(true)); httpServer.stop(); assertThat("The server should be stopped",httpServer.isStarted(), is(false)); diff --git a/junit/src/main/java/cucumber/api/junit/Cucumber.java b/junit/src/main/java/cucumber/api/junit/Cucumber.java index 66a0f2c587..ba9fdba272 100644 --- a/junit/src/main/java/cucumber/api/junit/Cucumber.java +++ b/junit/src/main/java/cucumber/api/junit/Cucumber.java @@ -83,9 +83,9 @@ protected void runChild(FeatureRunner child, RunNotifier notifier) { @Override public void run(RunNotifier notifier) { - runtime.runBeforeTestsHooks(jUnitReporter); + runtime.runBeforeAllHooks(jUnitReporter); super.run(notifier); - runtime.runAfterTestsHooks(jUnitReporter); + runtime.runAfterAllHooks(jUnitReporter); jUnitReporter.done(); jUnitReporter.close(); runtime.printSummary(); diff --git a/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java b/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java index 49cca88458..d5b4778b13 100644 --- a/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java +++ b/junit/src/test/java/cucumber/runtime/junit/CucumberTest.java @@ -83,8 +83,8 @@ public void testRun_verify_that_preTests_and_postTests_hooks_are_executed() thro Whitebox.setInternalState(cucumber, "runtime", runtime); RunNotifier runNotifier = new RunNotifier(); cucumber.run(runNotifier); - verify(runtime, times(1)).runBeforeTestsHooks(any(Reporter.class)); - verify(runtime, times(1)).runAfterTestsHooks(any(Reporter.class)); + verify(runtime, times(1)).runBeforeAllHooks(any(Reporter.class)); + verify(runtime, times(1)).runAfterAllHooks(any(Reporter.class)); verify(runtime, times(1)).printSummary(); verifyNoMoreInteractions(runtime); }