diff --git a/cucumber-core/pom.xml b/cucumber-core/pom.xml index a7e9d6917f..a226cdc4df 100644 --- a/cucumber-core/pom.xml +++ b/cucumber-core/pom.xml @@ -20,7 +20,6 @@ 2.10.0 3.0 0.2 - 5.14.2 4.5.10 1.0.4 @@ -143,12 +142,6 @@ junit-jupiter test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - io.vertx vertx-web diff --git a/cucumber-core/src/test/java/io/cucumber/core/order/PickleOrderTest.java b/cucumber-core/src/test/java/io/cucumber/core/order/PickleOrderTest.java index 9578eb1e67..37e0102ce7 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/order/PickleOrderTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/order/PickleOrderTest.java @@ -1,11 +1,9 @@ package io.cucumber.core.order; import io.cucumber.core.gherkin.Pickle; +import io.cucumber.core.gherkin.Step; import io.cucumber.plugin.event.Location; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import java.net.URI; import java.util.Arrays; @@ -13,27 +11,14 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.mockito.Mockito.when; -@ExtendWith(MockitoExtension.class) class PickleOrderTest { - @Mock - Pickle firstPickle; - - @Mock - Pickle secondPickle; - - @Mock - Pickle thirdPickle; - @Test void lexical_uri_order() { - when(firstPickle.getUri()).thenReturn(URI.create("file:com/example/a.feature")); - when(firstPickle.getLocation()).thenReturn(new Location(2, -1)); - when(secondPickle.getUri()).thenReturn(URI.create("file:com/example/a.feature")); - when(secondPickle.getLocation()).thenReturn(new Location(3, -1)); - when(thirdPickle.getUri()).thenReturn(URI.create("file:com/example/b.feature")); + Pickle firstPickle = new StubPickle(new Location(2, -1), URI.create("file:com/example/a.feature")); + Pickle secondPickle = new StubPickle(new Location(3, -1), URI.create("file:com/example/a.feature")); + Pickle thirdPickle = new StubPickle(null, URI.create("file:com/example/b.feature")); PickleOrder order = StandardPickleOrders.lexicalUriOrder(); List pickles = order.orderPickles(Arrays.asList(thirdPickle, secondPickle, firstPickle)); @@ -42,11 +27,9 @@ void lexical_uri_order() { @Test void reverse_lexical_uri_order() { - when(firstPickle.getUri()).thenReturn(URI.create("file:com/example/a.feature")); - when(firstPickle.getLocation()).thenReturn(new Location(2, -1)); - when(secondPickle.getUri()).thenReturn(URI.create("file:com/example/a.feature")); - when(secondPickle.getLocation()).thenReturn(new Location(3, -1)); - when(thirdPickle.getUri()).thenReturn(URI.create("file:com/example/b.feature")); + Pickle firstPickle = new StubPickle(new Location(2, -1), URI.create("file:com/example/a.feature")); + Pickle secondPickle = new StubPickle(new Location(3, -1), URI.create("file:com/example/a.feature")); + Pickle thirdPickle = new StubPickle(null, URI.create("file:com/example/b.feature")); PickleOrder order = StandardPickleOrders.reverseLexicalUriOrder(); List pickles = order.orderPickles(Arrays.asList(secondPickle, thirdPickle, firstPickle)); @@ -55,9 +38,67 @@ void reverse_lexical_uri_order() { @Test void random_order() { + Pickle firstPickle = new StubPickle(new Location(2, -1), URI.create("file:com/example/a.feature")); + Pickle secondPickle = new StubPickle(new Location(3, -1), URI.create("file:com/example/a.feature")); + Pickle thirdPickle = new StubPickle(null, URI.create("file:com/example/b.feature")); + PickleOrder order = StandardPickleOrders.random(42); List pickles = order.orderPickles(Arrays.asList(firstPickle, secondPickle, thirdPickle)); assertThat(pickles, contains(secondPickle, firstPickle, thirdPickle)); } + private static class StubPickle implements Pickle { + private final Location location; + private final URI uri; + + public StubPickle(Location location, URI uri) { + this.location = location; + this.uri = uri; + } + + @Override + public String getKeyword() { + return null; + } + + @Override + public String getLanguage() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public Location getScenarioLocation() { + return null; + } + + @Override + public List getSteps() { + return null; + } + + @Override + public List getTags() { + return null; + } + + @Override + public URI getUri() { + return uri; + } + + @Override + public String getId() { + return null; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/CanonicalEventOrderTest.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/CanonicalEventOrderTest.java index da413f7885..5e4b6dd55c 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/plugin/CanonicalEventOrderTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/CanonicalEventOrderTest.java @@ -6,7 +6,6 @@ import io.cucumber.plugin.event.SnippetsSuggestedEvent; import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion; import io.cucumber.plugin.event.Status; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestCaseStarted; import io.cucumber.plugin.event.TestRunFinished; import io.cucumber.plugin.event.TestRunStarted; @@ -27,8 +26,6 @@ import static org.hamcrest.number.OrderingComparison.greaterThan; import static org.hamcrest.number.OrderingComparison.lessThan; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; class CanonicalEventOrderTest { @@ -81,10 +78,7 @@ class CanonicalEventOrderTest { new Result(Status.PASSED, Duration.ZERO, null)); private static TestCaseStarted createTestCaseEvent(Instant instant, URI uri, int line) { - final TestCase testCase = mock(TestCase.class); - given(testCase.getUri()).willReturn(uri); - given(testCase.getLocation()).willReturn(new Location(line, -1)); - return new TestCaseStarted(instant, testCase); + return new TestCaseStarted(instant, new StubTestCase(uri, new Location(line, -1))); } @Test diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java index 74a5cda275..3766f4499c 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginFactoryTest.java @@ -10,10 +10,8 @@ import io.cucumber.plugin.EventListener; import io.cucumber.plugin.event.EventHandler; import io.cucumber.plugin.event.EventPublisher; -import io.cucumber.plugin.event.PickleStepTestStep; import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.Status; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestRunFinished; import io.cucumber.plugin.event.TestRunStarted; import io.cucumber.plugin.event.TestStepFinished; @@ -48,7 +46,6 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; class PluginFactoryTest { @@ -196,8 +193,8 @@ void plugin_does_not_buffer_its_output() { EventBus bus = new TimeServiceEventBus(new ClockStub(ZERO), UUID::randomUUID); plugin.setEventPublisher(bus); Result result = new Result(Status.PASSED, ZERO, null); - TestStepFinished event = new TestStepFinished(bus.getInstant(), mock(TestCase.class), - mock(PickleStepTestStep.class), result); + TestStepFinished event = new TestStepFinished(bus.getInstant(), new StubTestCase(), + new StubPickleStepTestStep(), result); bus.send(event); assertThat(mockSystemOut.toString(), is(not(equalTo("")))); diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginsTest.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginsTest.java index 307057c5c9..7b1b6d7c16 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginsTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/PluginsTest.java @@ -6,79 +6,127 @@ import io.cucumber.plugin.EventListener; import io.cucumber.plugin.StrictAware; import io.cucumber.plugin.event.Event; +import io.cucumber.plugin.event.EventHandler; import io.cucumber.plugin.event.EventPublisher; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -@ExtendWith({ MockitoExtension.class }) + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + class PluginsTest { private final PluginFactory pluginFactory = new PluginFactory(); - @Mock - private EventPublisher rootEventPublisher; - @Captor - private ArgumentCaptor eventPublisher; @Test void shouldSetStrictOnPlugin() { RuntimeOptions runtimeOptions = RuntimeOptions.defaultOptions(); Plugins plugins = new Plugins(pluginFactory, runtimeOptions); - StrictAware plugin = mock(StrictAware.class); + MockStrictAware plugin = new MockStrictAware(); plugins.addPlugin(plugin); - verify(plugin).setStrict(true); + assertTrue(plugin.strict); } @Test void shouldSetMonochromeOnPlugin() { RuntimeOptions runtimeOptions = RuntimeOptions.defaultOptions(); Plugins plugins = new Plugins(pluginFactory, runtimeOptions); - ColorAware plugin = mock(ColorAware.class); + MockColorAware plugin = new MockColorAware(); plugins.addPlugin(plugin); - verify(plugin).setMonochrome(false); + assertFalse(plugin.monochrome); } @Test void shouldSetConcurrentEventListener() { RuntimeOptions runtimeOptions = RuntimeOptions.defaultOptions(); Plugins plugins = new Plugins(pluginFactory, runtimeOptions); - ConcurrentEventListener plugin = mock(ConcurrentEventListener.class); + MockConcurrentEventListener plugin = new MockConcurrentEventListener(); + EventPublisher rootEventPublisher = new MockEventPublisher(); plugins.addPlugin(plugin); plugins.setEventBusOnEventListenerPlugins(rootEventPublisher); - verify(plugin, times(1)).setEventPublisher(rootEventPublisher); + + assertIterableEquals(List.of(rootEventPublisher), plugin.eventPublishers); } @Test void shouldSetNonConcurrentEventListener() { RuntimeOptions runtimeOptions = RuntimeOptions.defaultOptions(); Plugins plugins = new Plugins(pluginFactory, runtimeOptions); - EventListener plugin = mock(EventListener.class); + MockEventListener plugin = new MockEventListener(); + EventPublisher rootEventPublisher = new MockEventPublisher(); plugins.addPlugin(plugin); plugins.setSerialEventBusOnEventListenerPlugins(rootEventPublisher); - verify(plugin, times(1)).setEventPublisher(eventPublisher.capture()); - assertThat(eventPublisher.getValue().getClass(), is(equalTo(CanonicalOrderEventPublisher.class))); + + assertEquals(1, plugin.eventPublishers.size()); + assertInstanceOf(CanonicalOrderEventPublisher.class, plugin.eventPublishers.get(0)); } @Test void shouldRegisterCanonicalOrderEventPublisherWithRootEventPublisher() { RuntimeOptions runtimeOptions = RuntimeOptions.defaultOptions(); Plugins plugins = new Plugins(pluginFactory, runtimeOptions); - EventListener plugin = mock(EventListener.class); + MockEventListener plugin = new MockEventListener(); + MockEventPublisher rootEventPublisher = new MockEventPublisher(); plugins.addPlugin(plugin); plugins.setSerialEventBusOnEventListenerPlugins(rootEventPublisher); - verify(rootEventPublisher, times(1)).registerHandlerFor(eq(Event.class), ArgumentMatchers.any()); + + List> eventHandlers = rootEventPublisher.handlers.get(Event.class); + assertNotNull(eventHandlers); + assertEquals(1, eventHandlers.size()); + } + + @SuppressWarnings("deprecation") + private static class MockStrictAware implements StrictAware { + Boolean strict; + @Override + public void setStrict(boolean strict) { + this.strict = strict; + } } + private static class MockColorAware implements ColorAware { + Boolean monochrome; + @Override + public void setMonochrome(boolean monochrome) { + this.monochrome = monochrome; + } + } + + private static class MockConcurrentEventListener implements ConcurrentEventListener { + final List eventPublishers = new ArrayList<>(); + @Override + public void setEventPublisher(EventPublisher publisher) { + eventPublishers.add(publisher); + } + } + + private static class MockEventListener implements EventListener { + final List eventPublishers = new ArrayList<>(); + @Override + public void setEventPublisher(EventPublisher publisher) { + eventPublishers.add(publisher); + } + } + + private static class MockEventPublisher implements EventPublisher { + final Map, List>> handlers = new HashMap<>(); + @Override + public void registerHandlerFor(Class eventType, EventHandler handler) { + List> eventHandlers = handlers.computeIfAbsent(eventType, key -> new ArrayList<>()); + eventHandlers.add(handler); + } + + @Override + public void removeHandlerFor(Class eventType, EventHandler handler) { + + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java index 2a3069e354..b506ba8201 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/ProgressFormatterTest.java @@ -2,19 +2,25 @@ import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.runtime.TimeServiceEventBus; -import io.cucumber.plugin.event.HookTestStep; +import io.cucumber.plugin.event.Argument; +import io.cucumber.plugin.event.Location; import io.cucumber.plugin.event.PickleStepTestStep; import io.cucumber.plugin.event.Result; +import io.cucumber.plugin.event.Step; +import io.cucumber.plugin.event.StepArgument; import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestRunFinished; +import io.cucumber.plugin.event.TestStep; import io.cucumber.plugin.event.TestStepFinished; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; +import java.net.URI; import java.time.Clock; import java.time.Duration; import java.time.Instant; +import java.util.List; import java.util.UUID; import static io.cucumber.core.plugin.Bytes.bytes; @@ -24,13 +30,14 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.text.IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace; -import static org.mockito.Mockito.mock; class ProgressFormatterTest { final EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); final ByteArrayOutputStream out = new ByteArrayOutputStream(); final ProgressFormatter formatter = new ProgressFormatter(out); + private final StubTestCase mocktestCase = new StubTestCase(); + private final StubPickleStepTestStep stubPickleStepTestStep = new StubPickleStepTestStep(); @BeforeEach void setup() { @@ -47,7 +54,7 @@ void prints_empty_line_for_empty_test_run() { @Test void prints_empty_line_and_green_dot_for_passing_test_run() { Result result = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), result)); + bus.send(new TestStepFinished(Instant.now(), mocktestCase, stubPickleStepTestStep, result)); bus.send(new TestRunFinished(Instant.now(), result)); assertThat(out, bytes(equalToCompressingWhiteSpace(AnsiEscapes.GREEN + "." + AnsiEscapes.RESET + "\n"))); } @@ -55,35 +62,142 @@ void prints_empty_line_and_green_dot_for_passing_test_run() { @Test void print_green_dot_for_passing_step() { Result result = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), result)); + bus.send(new TestStepFinished(Instant.now(), mocktestCase, stubPickleStepTestStep, result)); assertThat(out, bytes(equalTo(AnsiEscapes.GREEN + "." + AnsiEscapes.RESET))); } @Test void print_yellow_U_for_undefined_step() { Result result = new Result(UNDEFINED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), result)); + bus.send(new TestStepFinished(Instant.now(), mocktestCase, stubPickleStepTestStep, result)); assertThat(out, bytes(equalTo(AnsiEscapes.YELLOW + "U" + AnsiEscapes.RESET))); } @Test void print_nothing_for_passed_hook() { Result result = new Result(PASSED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), result)); + bus.send(new TestStepFinished(Instant.now(), mocktestCase, stubPickleStepTestStep, result)); } @Test void print_red_F_for_failed_step() { Result result = new Result(FAILED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(PickleStepTestStep.class), result)); + bus.send(new TestStepFinished(Instant.now(), mocktestCase, stubPickleStepTestStep, result)); assertThat(out, bytes(equalTo(AnsiEscapes.RED + "F" + AnsiEscapes.RESET))); } @Test void print_red_F_for_failed_hook() { Result result = new Result(FAILED, Duration.ZERO, null); - bus.send(new TestStepFinished(Instant.now(), mock(TestCase.class), mock(HookTestStep.class), result)); + bus.send(new TestStepFinished(Instant.now(), mocktestCase, stubPickleStepTestStep, result)); assertThat(out, bytes(equalTo(AnsiEscapes.RED + "F" + AnsiEscapes.RESET))); } + @Test + void print_red_F_for_failed_hook_monochrome() { + // Given + Result result = new Result(FAILED, Duration.ZERO, null); + formatter.setMonochrome(true); + + // When + bus.send(new TestStepFinished(Instant.now(), mocktestCase, stubPickleStepTestStep, result)); + + // Then + assertThat(out, bytes(equalTo("F"))); + formatter.setMonochrome(false); + } + + private static class StubTestCase implements TestCase { + @Override + public Integer getLine() { + return null; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getKeyword() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getScenarioDesignation() { + return null; + } + + @Override + public List getTags() { + return null; + } + + @Override + public List getTestSteps() { + return null; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public UUID getId() { + return null; + } + } + + private static class StubPickleStepTestStep implements PickleStepTestStep { + @Override + public String getPattern() { + return null; + } + + @Override + public Step getStep() { + return null; + } + + @Override + public List getDefinitionArgument() { + return null; + } + + @Override + public StepArgument getStepArgument() { + return null; + } + + @Override + public int getStepLine() { + return 0; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public String getStepText() { + return null; + } + + @Override + public String getCodeLocation() { + return null; + } + + @Override + public UUID getId() { + return null; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/StubPickleStepTestStep.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/StubPickleStepTestStep.java new file mode 100644 index 0000000000..e04e8c1f89 --- /dev/null +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/StubPickleStepTestStep.java @@ -0,0 +1,70 @@ +package io.cucumber.core.plugin; + +import io.cucumber.plugin.event.Argument; +import io.cucumber.plugin.event.PickleStepTestStep; +import io.cucumber.plugin.event.Step; +import io.cucumber.plugin.event.StepArgument; + +import java.net.URI; +import java.util.List; +import java.util.UUID; + +public class StubPickleStepTestStep implements PickleStepTestStep { + private final String pattern; + private final String stepText; + + public StubPickleStepTestStep() { + this.pattern = null; + this.stepText = null; + } + + public StubPickleStepTestStep(String pattern, String stepText) { + this.pattern = pattern; + this.stepText = stepText; + } + + @Override + public String getPattern() { + return pattern; + } + + @Override + public Step getStep() { + return null; + } + + @Override + public List getDefinitionArgument() { + return null; + } + + @Override + public StepArgument getStepArgument() { + return null; + } + + @Override + public int getStepLine() { + return 0; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public String getStepText() { + return stepText; + } + + @Override + public String getCodeLocation() { + return null; + } + + @Override + public UUID getId() { + return null; + } +} diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/StubTestCase.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/StubTestCase.java new file mode 100644 index 0000000000..6f67f5d138 --- /dev/null +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/StubTestCase.java @@ -0,0 +1,69 @@ +package io.cucumber.core.plugin; + +import io.cucumber.plugin.event.Location; +import io.cucumber.plugin.event.TestCase; +import io.cucumber.plugin.event.TestStep; + +import java.net.URI; +import java.util.List; +import java.util.UUID; + +public class StubTestCase implements TestCase { + private final URI uri; + private final Location location; + + public StubTestCase() { + this.uri = null; + this.location = null; + } + + public StubTestCase(URI uri, Location location) { + this.uri = uri; + this.location = location; + } + + @Override + public Integer getLine() { + return null; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public String getKeyword() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getScenarioDesignation() { + return null; + } + + @Override + public List getTags() { + return null; + } + + @Override + public List getTestSteps() { + return null; + } + + @Override + public URI getUri() { + return uri; + } + + @Override + public UUID getId() { + return null; + } +} diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinterTest.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinterTest.java index af319a45fa..adbbd172c5 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinterTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinterTest.java @@ -5,7 +5,6 @@ import io.cucumber.plugin.event.Status; import io.cucumber.plugin.event.StepDefinedEvent; import io.cucumber.plugin.event.StepDefinition; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestRunFinished; import io.cucumber.plugin.event.TestStep; import io.cucumber.plugin.event.TestStepFinished; @@ -19,8 +18,6 @@ import static io.cucumber.core.plugin.Bytes.bytes; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.text.IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class UnusedStepsSummaryPrinterTest { @@ -36,12 +33,12 @@ void verifyUnusedStepsPrinted() { bus.send(new StepDefinedEvent(bus.getInstant(), mockStepDef("my/belly.feature:3", "a few cukes"))); bus.send(new StepDefinedEvent(bus.getInstant(), mockStepDef("my/tummy.feature:5", "some more cukes"))); bus.send(new StepDefinedEvent(bus.getInstant(), mockStepDef("my/gut.feature:7", "even more cukes"))); - bus.send(new TestStepFinished(bus.getInstant(), mock(TestCase.class), mockTestStep("my/belly.feature:3"), + bus.send(new TestStepFinished(bus.getInstant(), new StubTestCase(), new StubTestStep("my/belly.feature:3"), new Result(Status.UNUSED, Duration.ZERO, null))); bus.send(new StepDefinedEvent(bus.getInstant(), mockStepDef("my/belly.feature:3", "a few cukes"))); bus.send(new StepDefinedEvent(bus.getInstant(), mockStepDef("my/tummy.feature:5", "some more cukes"))); bus.send(new StepDefinedEvent(bus.getInstant(), mockStepDef("my/gut.feature:7", "even more cukes"))); - bus.send(new TestStepFinished(bus.getInstant(), mock(TestCase.class), mockTestStep("my/gut.feature:7"), + bus.send(new TestStepFinished(bus.getInstant(), new StubTestCase(), new StubTestStep("my/gut.feature:7"), new Result(Status.UNUSED, Duration.ZERO, null))); bus.send(new TestRunFinished(bus.getInstant(), new Result(Status.PASSED, Duration.ZERO, null))); @@ -54,10 +51,21 @@ private static StepDefinition mockStepDef(String location, String pattern) { return new StepDefinition(location, pattern); } - private static TestStep mockTestStep(String location) { - TestStep testStep = mock(TestStep.class); - when(testStep.getCodeLocation()).thenReturn(location); - return testStep; - } + public static class StubTestStep implements TestStep { + private final String codeLocation; + + public StubTestStep(String codeLocation) { + this.codeLocation = codeLocation; + } + @Override + public String getCodeLocation() { + return codeLocation; + } + + @Override + public UUID getId() { + return null; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/plugin/UsageFormatterTest.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/UsageFormatterTest.java index 00cc379a35..ece53df6c5 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/plugin/UsageFormatterTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/UsageFormatterTest.java @@ -3,13 +3,11 @@ import io.cucumber.plugin.event.PickleStepTestStep; import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.Status; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestStep; import io.cucumber.plugin.event.TestStepFinished; import org.json.JSONException; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import java.io.ByteArrayOutputStream; import java.io.OutputStream; @@ -26,8 +24,6 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.number.IsCloseTo.closeTo; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; class UsageFormatterTest { @@ -38,11 +34,11 @@ class UsageFormatterTest { void resultWithPassedStep() { OutputStream out = new ByteArrayOutputStream(); UsageFormatter usageFormatter = new UsageFormatter(out); - TestStep testStep = mockTestStep(); + TestStep testStep = new StubPickleStepTestStep("stepDef", "step"); Result result = new Result(Status.PASSED, Duration.ofMillis(12345L), null); usageFormatter - .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, mock(TestCase.class), testStep, result)); + .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, new StubTestCase(), testStep, result)); Map> usageMap = usageFormatter.usageMap; assertThat(usageMap.size(), is(equalTo(1))); @@ -53,26 +49,19 @@ void resultWithPassedStep() { assertThat(durationEntries.get(0).getDurations().get(0).getDuration(), is(closeTo(12.345, EPSILON))); } - private PickleStepTestStep mockTestStep() { - PickleStepTestStep testStep = mock(PickleStepTestStep.class, Mockito.RETURNS_MOCKS); - when(testStep.getPattern()).thenReturn("stepDef"); - when(testStep.getStepText()).thenReturn("step"); - return testStep; - } - @Test void resultWithPassedAndFailedStep() { OutputStream out = new ByteArrayOutputStream(); UsageFormatter usageFormatter = new UsageFormatter(out); - TestStep testStep = mockTestStep(); + TestStep testStep = new StubPickleStepTestStep("stepDef", "step"); Result passed = new Result(Status.PASSED, Duration.ofSeconds(12345L), null); usageFormatter - .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, mock(TestCase.class), testStep, passed)); + .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, new StubTestCase(), testStep, passed)); Result failed = new Result(Status.FAILED, Duration.ZERO, null); usageFormatter - .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, mock(TestCase.class), testStep, failed)); + .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, new StubTestCase(), testStep, failed)); Map> usageMap = usageFormatter.usageMap; assertThat(usageMap.size(), is(equalTo(1))); @@ -87,11 +76,11 @@ void resultWithPassedAndFailedStep() { void resultWithZeroDuration() { OutputStream out = new ByteArrayOutputStream(); UsageFormatter usageFormatter = new UsageFormatter(out); - TestStep testStep = mockTestStep(); + TestStep testStep = new StubPickleStepTestStep("stepDef", "step"); Result result = new Result(Status.PASSED, Duration.ZERO, null); usageFormatter - .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, mock(TestCase.class), testStep, result)); + .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, new StubTestCase(), testStep, result)); Map> usageMap = usageFormatter.usageMap; assertThat(usageMap.size(), is(equalTo(1))); @@ -107,11 +96,11 @@ void resultWithZeroDuration() { void resultWithNullDuration() { OutputStream out = new ByteArrayOutputStream(); UsageFormatter usageFormatter = new UsageFormatter(out); - PickleStepTestStep testStep = mockTestStep(); + PickleStepTestStep testStep = new StubPickleStepTestStep("stepDef", "step"); Result result = new Result(Status.PASSED, Duration.ZERO, null); usageFormatter - .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, mock(TestCase.class), testStep, result)); + .handleTestStepFinished(new TestStepFinished(Instant.EPOCH, new StubTestCase(), testStep, result)); Map> usageMap = usageFormatter.usageMap; assertThat(usageMap.size(), is(equalTo(1))); diff --git a/cucumber-core/src/test/java/io/cucumber/core/resource/ClasspathScannerTest.java b/cucumber-core/src/test/java/io/cucumber/core/resource/ClasspathScannerTest.java index c664b86eec..4f0a05e3c2 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/resource/ClasspathScannerTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/resource/ClasspathScannerTest.java @@ -11,7 +11,9 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; +import java.util.Enumeration; import java.util.List; +import java.util.Map; import static java.util.Collections.enumeration; import static java.util.Collections.singletonList; @@ -20,8 +22,6 @@ import static org.hamcrest.collection.IsEmptyCollection.empty; import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @WithLogRecordListener class ClasspathScannerTest { @@ -64,8 +64,6 @@ void scanForClassesInNonExistingPackage() { @Test void scanForResourcesInUnsupportedFileSystem(LogRecordListener logRecordListener) throws IOException { - ClassLoader classLoader = mock(ClassLoader.class); - ClasspathScanner scanner = new ClasspathScanner(() -> classLoader); URLStreamHandler handler = new URLStreamHandler() { @Override protected URLConnection openConnection(URL u) { @@ -73,10 +71,25 @@ protected URLConnection openConnection(URL u) { } }; URL resourceUrl = new URL(null, "bundle-resource:com/cucumber/bundle", handler); - when(classLoader.getResources("com/cucumber/bundle")).thenReturn(enumeration(singletonList(resourceUrl))); + ClassLoader classLoader = new MockClassLoader( + Map.of("com/cucumber/bundle", enumeration(singletonList(resourceUrl)))); + ClasspathScanner scanner = new ClasspathScanner(() -> classLoader); assertThat(scanner.scanForClassesInPackage("com.cucumber.bundle"), empty()); assertThat(logRecordListener.getLogRecords().get(0).getMessage(), containsString("Failed to find resources for 'bundle-resource:com/cucumber/bundle'")); } + public static class MockClassLoader extends ClassLoader { + private final Map> resources; + + public MockClassLoader(Map> resources) { + this.resources = resources; + } + + @Override + public Enumeration getResources(String name) { + return resources.get(name); + } + } + } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionMatchTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionMatchTest.java index 1383c8df89..14ff905e33 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionMatchTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionMatchTest.java @@ -1,8 +1,10 @@ package io.cucumber.core.runner; +import io.cucumber.core.eventbus.IncrementingUuidGenerator; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; import io.cucumber.core.gherkin.Step; +import io.cucumber.core.plugin.StubTestCase; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; @@ -13,7 +15,6 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; class AmbiguousStepDefinitionMatchTest { @@ -25,10 +26,12 @@ class AmbiguousStepDefinitionMatchTest { private final AmbiguousStepDefinitionsException e = new AmbiguousStepDefinitionsException(step, emptyList()); private final AmbiguousPickleStepDefinitionsMatch match = new AmbiguousPickleStepDefinitionsMatch( URI.create("file:path/to.feature"), step, e); + private final TestCaseState mockTestCaseState = new TestCaseState(new StubEventBus(), + new IncrementingUuidGenerator().generateId(), new StubTestCase()); @Test void throws_ambiguous_step_definitions_exception_when_run() { - Executable testMethod = () -> match.runStep(mock(TestCaseState.class)); + Executable testMethod = () -> match.runStep(mockTestCaseState); AmbiguousStepDefinitionsException actualThrown = assertThrows(AmbiguousStepDefinitionsException.class, testMethod); assertThat(actualThrown.getMessage(), is(equalTo( @@ -37,7 +40,7 @@ void throws_ambiguous_step_definitions_exception_when_run() { @Test void throws_ambiguous_step_definitions_exception_when_dry_run() { - Executable testMethod = () -> match.dryRunStep(mock(TestCaseState.class)); + Executable testMethod = () -> match.dryRunStep(mockTestCaseState); AmbiguousStepDefinitionsException actualThrown = assertThrows(AmbiguousStepDefinitionsException.class, testMethod); assertThat(actualThrown.getMessage(), is(equalTo( diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionsExceptionTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionsExceptionTest.java index 80db4b66ef..61885d5e70 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionsExceptionTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/AmbiguousStepDefinitionsExceptionTest.java @@ -1,10 +1,12 @@ package io.cucumber.core.runner; +import io.cucumber.core.backend.StubStepDefinition; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; import io.cucumber.core.gherkin.Step; import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.List; import static java.util.Arrays.asList; @@ -13,8 +15,6 @@ import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class AmbiguousStepDefinitionsExceptionTest { @@ -27,13 +27,13 @@ void can_report_ambiguous_step_definitions() { Step mockPickleStep = feature.getPickles().get(0).getSteps().get(0); - PickleStepDefinitionMatch mockPickleStepDefinitionMatchOne = mock(PickleStepDefinitionMatch.class); - when(mockPickleStepDefinitionMatchOne.getPattern()).thenReturn("PickleStepDefinitionMatchOne_Pattern"); - when(mockPickleStepDefinitionMatchOne.getLocation()).thenReturn("PickleStepDefinitionMatchOne_Location"); + PickleStepDefinitionMatch mockPickleStepDefinitionMatchOne = new PickleStepDefinitionMatch(new ArrayList<>(), + new StubStepDefinition("PickleStepDefinitionMatchOne_Pattern", "PickleStepDefinitionMatchOne_Location"), + null, null); - PickleStepDefinitionMatch mockPickleStepDefinitionMatchTwo = mock(PickleStepDefinitionMatch.class); - when(mockPickleStepDefinitionMatchTwo.getPattern()).thenReturn("PickleStepDefinitionMatchTwo_Pattern"); - when(mockPickleStepDefinitionMatchTwo.getLocation()).thenReturn("PickleStepDefinitionMatchTwo_Location"); + PickleStepDefinitionMatch mockPickleStepDefinitionMatchTwo = new PickleStepDefinitionMatch(new ArrayList<>(), + new StubStepDefinition("PickleStepDefinitionMatchTwo_Pattern", "PickleStepDefinitionMatchTwo_Location"), + null, null); List matches = asList(mockPickleStepDefinitionMatchOne, mockPickleStepDefinitionMatchTwo); diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/CachingGlueTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/CachingGlueTest.java index c67d33d9e3..2c1ad4cce7 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/CachingGlueTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/CachingGlueTest.java @@ -1,11 +1,14 @@ package io.cucumber.core.runner; +import io.cucumber.core.backend.CucumberBackendException; +import io.cucumber.core.backend.CucumberInvocationTargetException; import io.cucumber.core.backend.DataTableTypeDefinition; import io.cucumber.core.backend.DefaultDataTableCellTransformerDefinition; import io.cucumber.core.backend.DefaultDataTableEntryTransformerDefinition; import io.cucumber.core.backend.DefaultParameterTransformerDefinition; import io.cucumber.core.backend.DocStringTypeDefinition; import io.cucumber.core.backend.HookDefinition; +import io.cucumber.core.backend.ParameterInfo; import io.cucumber.core.backend.ParameterTypeDefinition; import io.cucumber.core.backend.ScenarioScoped; import io.cucumber.core.backend.SourceReference; @@ -32,6 +35,7 @@ import java.net.URI; import java.time.Clock; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -48,8 +52,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class CachingGlueTest { @@ -58,14 +60,10 @@ class CachingGlueTest { @Test void throws_duplicate_error_on_dupe_stepdefs() { - StepDefinition a = mock(StepDefinition.class); - when(a.getPattern()).thenReturn("hello"); - when(a.getLocation()).thenReturn("foo.bf:10"); + StepDefinition a = new StubStepDefinitionWithPatternAndLocation("hello", "foo.bf:10"); glue.addStepDefinition(a); - StepDefinition b = mock(StepDefinition.class); - when(b.getPattern()).thenReturn("hello"); - when(b.getLocation()).thenReturn("bar.bf:90"); + StepDefinition b = new StubStepDefinitionWithPatternAndLocation("hello", "bar.bf:90"); glue.addStepDefinition(b); DuplicateStepDefinitionException exception = assertThrows( @@ -853,4 +851,39 @@ public boolean isDisposed() { } } + + private static class StubStepDefinitionWithPatternAndLocation implements StepDefinition { + private final String pattern; + private final String location; + + public StubStepDefinitionWithPatternAndLocation(String pattern, String location) { + this.pattern = pattern; + this.location = location; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return location; + } + + @Override + public void execute(Object[] args) throws CucumberBackendException, CucumberInvocationTargetException { + + } + + @Override + public List parameterInfos() { + return Collections.emptyList(); + } + + @Override + public String getPattern() { + return pattern; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/DuplicateStepDefinitionExceptionTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/DuplicateStepDefinitionExceptionTest.java index 63012ff6ea..d78b37592f 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/DuplicateStepDefinitionExceptionTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/DuplicateStepDefinitionExceptionTest.java @@ -1,31 +1,62 @@ package io.cucumber.core.runner; +import io.cucumber.core.backend.CucumberBackendException; +import io.cucumber.core.backend.CucumberInvocationTargetException; +import io.cucumber.core.backend.ParameterInfo; import io.cucumber.core.backend.StepDefinition; import org.junit.jupiter.api.Test; +import java.util.List; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class DuplicateStepDefinitionExceptionTest { @Test void can_report_duplicate_step_definitions() { - final StepDefinition mockStepDefinitionA = mock(StepDefinition.class); - when(mockStepDefinitionA.getLocation()).thenReturn("StepDefinitionA_Location"); - final StepDefinition mockStepDefinitionB = mock(StepDefinition.class); - when(mockStepDefinitionB.getLocation()).thenReturn("StepDefinitionB_Location"); - - DuplicateStepDefinitionException expectedThrown = new DuplicateStepDefinitionException(mockStepDefinitionA, - mockStepDefinitionB); + DuplicateStepDefinitionException expectedThrown = new DuplicateStepDefinitionException( + new StubStepDefinition("StepDefinitionA_Location"), + new StubStepDefinition("StepDefinitionB_Location")); assertAll( () -> assertThat(expectedThrown.getMessage(), is(equalTo("Duplicate step definitions in StepDefinitionA_Location and StepDefinitionB_Location"))), () -> assertThat(expectedThrown.getCause(), is(nullValue()))); } + public static class StubStepDefinition implements StepDefinition { + private final String location; + + public StubStepDefinition(String location) { + this.location = location; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return location; + } + + @Override + public void execute(Object[] args) throws CucumberBackendException, CucumberInvocationTargetException { + + } + + @Override + public List parameterInfos() { + return null; + } + + @Override + public String getPattern() { + return null; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/EventBusTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/EventBusTest.java index bbbcc49f3c..726d8bf0e5 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/EventBusTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/EventBusTest.java @@ -1,6 +1,8 @@ package io.cucumber.core.runner; import io.cucumber.core.eventbus.EventBus; +import io.cucumber.core.plugin.StubPickleStepTestStep; +import io.cucumber.core.plugin.StubTestCase; import io.cucumber.core.runtime.TimeServiceEventBus; import io.cucumber.plugin.event.EventHandler; import io.cucumber.plugin.event.PickleStepTestStep; @@ -10,50 +12,54 @@ import io.cucumber.plugin.event.TestStepFinished; import io.cucumber.plugin.event.TestStepStarted; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import static java.time.Duration.ZERO; import static java.time.Instant.EPOCH; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; +import static org.junit.jupiter.api.Assertions.assertEquals; -@ExtendWith(MockitoExtension.class) class EventBusTest { @Test void handlers_receive_the_events_they_registered_for() { - EventHandler handler = mock(EventHandler.class); - PickleStepTestStep testStep = mock(PickleStepTestStep.class); + MockEventHandler handler = new MockEventHandler<>(); + PickleStepTestStep testStep = new StubPickleStepTestStep(); Result result = new Result(Status.PASSED, ZERO, null); - TestCase testCase = mock(TestCase.class); + TestCase testCase = new StubTestCase(); TestStepFinished event = new TestStepFinished(EPOCH, testCase, testStep, result); EventBus bus = new TimeServiceEventBus(Clock.fixed(Instant.EPOCH, ZoneId.of("UTC")), UUID::randomUUID); bus.registerHandlerFor(TestStepFinished.class, handler); bus.send(event); - verify(handler).receive(event); + assertEquals(event, handler.events.get(0)); } @Test void handlers_do_not_receive_the_events_they_did_not_registered_for() { - EventHandler handler = mock(EventHandler.class); - PickleStepTestStep testStep = mock(PickleStepTestStep.class); - TestCase testCase = mock(TestCase.class); + MockEventHandler handler = new MockEventHandler<>(); + PickleStepTestStep testStep = new StubPickleStepTestStep(); + TestCase testCase = new StubTestCase(); TestStepStarted event = new TestStepStarted(EPOCH, testCase, testStep); EventBus bus = new TimeServiceEventBus(Clock.fixed(Instant.EPOCH, ZoneId.of("UTC")), UUID::randomUUID); bus.registerHandlerFor(TestStepFinished.class, handler); bus.send(event); - verify(handler, never()).receive(event); + assertEquals(0, handler.events.size()); } + private static class MockEventHandler implements EventHandler { + final List events = new ArrayList<>(); + @Override + public void receive(T event) { + events.add(event); + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/HookOrderTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/HookOrderTest.java index 4582a8b188..db860a0596 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/HookOrderTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/HookOrderTest.java @@ -3,6 +3,7 @@ import io.cucumber.core.backend.Glue; import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.StubStepDefinition; +import io.cucumber.core.backend.TestCaseState; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; @@ -10,8 +11,6 @@ import io.cucumber.core.options.RuntimeOptions; import io.cucumber.core.runtime.TimeServiceEventBus; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; import java.net.URI; import java.time.Clock; @@ -19,9 +18,7 @@ import java.util.List; import java.util.UUID; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertTrue; class HookOrderTest { @@ -34,10 +31,12 @@ class HookOrderTest { " Scenario: Test scenario\n" + " Given I have 4 cukes in my belly\n"); private final Pickle pickle = feature.getPickles().get(0); + private final List listener = new ArrayList<>(); @Test void before_hooks_execute_in_order() { - final List hooks = mockHooks(3, Integer.MAX_VALUE, 1, -1, 0, 10000, Integer.MIN_VALUE); + final List hooks = mockHooks(listener, 3, Integer.MAX_VALUE, 1, -1, 0, 10000, + Integer.MIN_VALUE); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -52,31 +51,37 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickle); - InOrder inOrder = inOrder(hooks.toArray()); - inOrder.verify(hooks.get(6)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(3)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(4)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(2)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(0)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(5)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(1)).execute(ArgumentMatchers.any()); + verifyHookDefinitionExecutedInOrder(); } - private List mockHooks(int... ordering) { + private void verifyHookDefinitionExecutedInOrder() { + long previousOrder = Long.MIN_VALUE; + for (HookDefinition hd : listener) { + assertTrue(hd.getOrder() >= previousOrder); + previousOrder = hd.getOrder(); + } + } + + private void verifyHookDefinitionExecutedInReverseOrder() { + long previousOrder = Long.MAX_VALUE; + for (HookDefinition hd : listener) { + assertTrue(hd.getOrder() <= previousOrder); + previousOrder = hd.getOrder(); + } + } + + private List mockHooks(List listener, int... ordering) { List hooks = new ArrayList<>(); for (int order : ordering) { - HookDefinition hook = mock(HookDefinition.class, "Mock number " + order); - when(hook.getOrder()).thenReturn(order); - when(hook.getTagExpression()).thenReturn(""); - when(hook.getLocation()).thenReturn("Mock location"); - hooks.add(hook); + hooks.add(new MockHookDefinition(order, listener)); } return hooks; } @Test void before_step_hooks_execute_in_order() { - final List hooks = mockHooks(3, Integer.MAX_VALUE, 1, -1, 0, 10000, Integer.MIN_VALUE); + final List hooks = mockHooks(listener, 3, Integer.MAX_VALUE, 1, -1, 0, 10000, + Integer.MIN_VALUE); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -91,19 +96,13 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickle); - InOrder inOrder = inOrder(hooks.toArray()); - inOrder.verify(hooks.get(6)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(3)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(4)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(2)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(0)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(5)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(1)).execute(ArgumentMatchers.any()); + verifyHookDefinitionExecutedInOrder(); } @Test void after_hooks_execute_in_reverse_order() { - final List hooks = mockHooks(Integer.MIN_VALUE, 2, Integer.MAX_VALUE, 4, -1, 0, 10000); + final List hooks = mockHooks(listener, Integer.MIN_VALUE, 2, Integer.MAX_VALUE, 4, -1, 0, + 10000); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -118,19 +117,13 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickle); - InOrder inOrder = inOrder(hooks.toArray()); - inOrder.verify(hooks.get(2)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(6)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(3)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(1)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(5)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(4)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(0)).execute(ArgumentMatchers.any()); + verifyHookDefinitionExecutedInReverseOrder(); } @Test void after_step_hooks_execute_in_reverse_order() { - final List hooks = mockHooks(Integer.MIN_VALUE, 2, Integer.MAX_VALUE, 4, -1, 0, 10000); + final List hooks = mockHooks(listener, Integer.MIN_VALUE, 2, Integer.MAX_VALUE, 4, -1, 0, + 10000); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -145,20 +138,13 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickle); - InOrder inOrder = inOrder(hooks.toArray()); - inOrder.verify(hooks.get(2)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(6)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(3)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(1)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(5)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(4)).execute(ArgumentMatchers.any()); - inOrder.verify(hooks.get(0)).execute(ArgumentMatchers.any()); + verifyHookDefinitionExecutedInReverseOrder(); } @Test void hooks_order_across_many_backends() { - final List backend1Hooks = mockHooks(3, Integer.MAX_VALUE, 1); - final List backend2Hooks = mockHooks(2, Integer.MAX_VALUE, 4); + final List backend1Hooks = mockHooks(listener, 3, Integer.MAX_VALUE, 1); + final List backend2Hooks = mockHooks(listener, 2, Integer.MAX_VALUE, 4); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -177,17 +163,41 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickle); - List allHooks = new ArrayList<>(); - allHooks.addAll(backend1Hooks); - allHooks.addAll(backend2Hooks); - - InOrder inOrder = inOrder(allHooks.toArray()); - inOrder.verify(backend1Hooks.get(2)).execute(ArgumentMatchers.any()); - inOrder.verify(backend2Hooks.get(0)).execute(ArgumentMatchers.any()); - inOrder.verify(backend1Hooks.get(0)).execute(ArgumentMatchers.any()); - inOrder.verify(backend2Hooks.get(2)).execute(ArgumentMatchers.any()); - inOrder.verify(backend1Hooks.get(1)).execute(ArgumentMatchers.any()); - inOrder.verify(backend2Hooks.get(1)).execute(ArgumentMatchers.any()); + verifyHookDefinitionExecutedInOrder(); } + private static class MockHookDefinition implements HookDefinition { + private final int order; + private final List listener; + + public MockHookDefinition(int order, List listener) { + this.order = order; + this.listener = listener; + } + + @Override + public void execute(TestCaseState state) { + listener.add(this); + } + + @Override + public String getTagExpression() { + return ""; + } + + @Override + public int getOrder() { + return order; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return "Mock location"; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/HookTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/HookTest.java index 8570ab96a5..79b9f59a13 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/HookTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/HookTest.java @@ -4,6 +4,8 @@ import io.cucumber.core.backend.Glue; import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.ObjectFactory; +import io.cucumber.core.backend.Snippet; +import io.cucumber.core.backend.TestCaseState; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; @@ -12,21 +14,18 @@ import io.cucumber.core.runtime.TimeServiceEventBus; import io.cucumber.core.snippets.TestSnippet; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; +import java.net.URI; import java.time.Clock; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.UUID; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; class HookTest { @@ -44,43 +43,23 @@ class HookTest { */ @Test void after_hooks_execute_before_objects_are_disposed() { - Backend backend = mock(Backend.class); - when(backend.getSnippet()).thenReturn(new TestSnippet()); - ObjectFactory objectFactory = mock(ObjectFactory.class); - final HookDefinition hook = mock(HookDefinition.class); - when(hook.getLocation()).thenReturn("hook-location"); - when(hook.getTagExpression()).thenReturn(""); - - doAnswer(invocation -> { - Glue glue = invocation.getArgument(0); - glue.addBeforeHook(hook); - return null; - }).when(backend).loadGlue(any(Glue.class), ArgumentMatchers.anyList()); - + final List eventListener = new ArrayList<>(); + final HookDefinition hook = new MockHookDefinition("", "hook-location", eventListener); + Backend backend = new StubBackend(hook, eventListener); + ObjectFactory objectFactory = new StubObjectFactory(); Runner runner = new Runner(bus, Collections.singleton(backend), objectFactory, runtimeOptions); runner.runPickle(pickle); - InOrder inOrder = inOrder(hook, backend); - inOrder.verify(backend).buildWorld(); - inOrder.verify(hook).execute(ArgumentMatchers.any()); - inOrder.verify(backend).disposeWorld(); + assertLinesMatch(eventListener, List.of("buildWorld", "execute", "disposeWorld")); } @Test void hook_throws_exception_with_name_when_tag_expression_is_invalid() { - Backend backend = mock(Backend.class); - when(backend.getSnippet()).thenReturn(new TestSnippet()); - ObjectFactory objectFactory = mock(ObjectFactory.class); - final HookDefinition hook = mock(HookDefinition.class); - when(hook.getLocation()).thenReturn("hook-location"); - when(hook.getTagExpression()).thenReturn("("); - - doAnswer(invocation -> { - Glue glue = invocation.getArgument(0); - glue.addBeforeHook(hook); - return null; - }).when(backend).loadGlue(any(Glue.class), ArgumentMatchers.anyList()); + final List eventListener = new ArrayList<>(); + final HookDefinition hook = new MockHookDefinition("(", "hook-location", eventListener); + Backend backend = new StubBackend(hook, eventListener); + ObjectFactory objectFactory = new StubObjectFactory(); RuntimeException e = assertThrows(RuntimeException.class, () -> new Runner(bus, Collections.singleton(backend), objectFactory, @@ -90,4 +69,92 @@ void hook_throws_exception_with_name_when_tag_expression_is_invalid() { is("Invalid tag expression at 'hook-location'")); } + private static class StubObjectFactory implements ObjectFactory { + @Override + public boolean addClass(Class glueClass) { + return false; + } + + @Override + public T getInstance(Class glueClass) { + return null; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + } + + private final static class StubBackend implements Backend { + private final HookDefinition beforeHook; + private final List eventListener; + + public StubBackend(HookDefinition beforeHook, List eventListener) { + this.beforeHook = beforeHook; + this.eventListener = eventListener; + } + + @Override + public void loadGlue(Glue glue, List gluePaths) { + glue.addBeforeHook(beforeHook); + } + + @Override + public void buildWorld() { + eventListener.add("buildWorld"); + } + + @Override + public void disposeWorld() { + eventListener.add("disposeWorld"); + } + + @Override + public Snippet getSnippet() { + return new TestSnippet(); + } + } + + private static final class MockHookDefinition implements HookDefinition { + private final String tagExpression; + private final String location; + private final List eventListener; + + public MockHookDefinition(String tagExpression, String location, List eventListener) { + this.tagExpression = tagExpression; + this.location = location; + this.eventListener = eventListener; + } + + @Override + public void execute(TestCaseState state) { + eventListener.add("execute"); + } + + @Override + public String getTagExpression() { + return tagExpression; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return location; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java index 569cf827e3..78ec6d8df8 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java @@ -1,18 +1,20 @@ package io.cucumber.core.runner; +import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; +import io.cucumber.messages.types.Envelope; +import io.cucumber.plugin.event.EventHandler; import io.cucumber.plugin.event.HookType; import io.cucumber.plugin.event.TestStepFinished; import io.cucumber.plugin.event.TestStepStarted; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; import java.time.Instant; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.UUID; import static io.cucumber.core.backend.Status.PASSED; @@ -20,10 +22,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; class HookTestStepTest { @@ -31,7 +31,9 @@ class HookTestStepTest { "Feature: Test feature\n" + " Scenario: Test scenario\n" + " Given I have 4 cukes in my belly\n"); - private final CoreHookDefinition hookDefintion = mock(CoreHookDefinition.class); + List listener = new ArrayList<>(); + private final CoreHookDefinition hookDefintion = CoreHookDefinition.create(new MockHookDefinition(listener), + UUID::randomUUID); private final HookDefinitionMatch definitionMatch = new HookDefinitionMatch(hookDefintion); private final TestCase testCase = new TestCase( UUID.randomUUID(), @@ -40,34 +42,26 @@ class HookTestStepTest { Collections.emptyList(), feature.getPickles().get(0), false); - private final EventBus bus = mock(EventBus.class); + private final EventBus bus = new MockEventBus(listener); private final UUID testExecutionId = UUID.randomUUID(); private final TestCaseState state = new TestCaseState(bus, testExecutionId, testCase); private final HookTestStep step = new HookTestStep(UUID.randomUUID(), HookType.AFTER_STEP, definitionMatch); - @BeforeEach - void init() { - Mockito.when(bus.getInstant()).thenReturn(Instant.now()); - } - @Test void run_does_run() { step.run(testCase, bus, state, ExecutionMode.RUN); - InOrder order = inOrder(bus, hookDefintion); - order.verify(bus).send(isA(TestStepStarted.class)); - order.verify(hookDefintion).execute(state); - order.verify(bus).send(isA(TestStepFinished.class)); + assertInstanceOf(TestStepStarted.class, listener.get(0)); + assertEquals("HookDefinition.execute", listener.get(1)); + assertInstanceOf(TestStepFinished.class, listener.get(2)); } @Test void run_does_dry_run() { step.run(testCase, bus, state, ExecutionMode.DRY_RUN); - InOrder order = inOrder(bus, hookDefintion); - order.verify(bus).send(isA(TestStepStarted.class)); - order.verify(hookDefintion, never()).execute(state); - order.verify(bus).send(isA(TestStepFinished.class)); + assertInstanceOf(TestStepStarted.class, listener.get(0)); + assertInstanceOf(TestStepFinished.class, listener.get(1)); } @Test @@ -91,4 +85,74 @@ void next_execution_mode_is_dry_run_when_step_passes_dry_run() { assertThat(state.getStatus(), is(equalTo(PASSED))); } + private static class MockHookDefinition implements HookDefinition { + private final List listener; + public MockHookDefinition(List listener) { + this.listener = listener; + } + + @Override + public void execute(io.cucumber.core.backend.TestCaseState state) { + listener.add("HookDefinition.execute"); + } + + @Override + public String getTagExpression() { + return ""; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return null; + } + } + + private static class MockEventBus implements EventBus { + private final List listener; + public MockEventBus(List listener) { + this.listener = listener; + } + + @Override + public Instant getInstant() { + return Instant.now(); + } + + @Override + public UUID generateId() { + return null; + } + + @Override + public void send(T event) { + if (!(event instanceof Envelope)) { + listener.add(event); + } + } + + @Override + public void sendAll(Iterable queue) { + + } + + @Override + public void registerHandlerFor(Class eventType, EventHandler handler) { + + } + + @Override + public void removeHandlerFor(Class eventType, EventHandler handler) { + + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java index 60e561bde9..d16252ebc8 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java @@ -1,28 +1,31 @@ package io.cucumber.core.runner; +import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.StubPendingException; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; import io.cucumber.core.gherkin.Pickle; +import io.cucumber.messages.types.Envelope; +import io.cucumber.plugin.event.EventHandler; import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.Status; import io.cucumber.plugin.event.TestCaseEvent; import io.cucumber.plugin.event.TestStepFinished; import io.cucumber.plugin.event.TestStepStarted; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; -import org.mockito.InOrder; -import org.mockito.Mockito; import org.opentest4j.TestAbortedException; import java.net.URI; import java.time.Instant; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Queue; import java.util.UUID; +import java.util.stream.Collectors; import static io.cucumber.core.backend.Status.FAILED; import static io.cucumber.core.backend.Status.PASSED; @@ -30,7 +33,6 @@ import static io.cucumber.core.backend.Status.SKIPPED; import static io.cucumber.plugin.event.HookType.AFTER_STEP; import static io.cucumber.plugin.event.HookType.BEFORE_STEP; -import static java.time.Duration.ZERO; import static java.time.Duration.ofMillis; import static java.time.Instant.ofEpochMilli; import static java.util.Collections.singletonList; @@ -38,17 +40,10 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentCaptor.forClass; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; class PickleStepTestStepTest { @@ -59,207 +54,239 @@ class PickleStepTestStepTest { private final Pickle pickle = feature.getPickles().get(0); private final TestCase testCase = new TestCase(UUID.randomUUID(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), pickle, false); - private final EventBus bus = mock(EventBus.class); - private final UUID testExecutionId = UUID.randomUUID(); - private final TestCaseState state = new TestCaseState(bus, testExecutionId, testCase); - private final PickleStepDefinitionMatch definitionMatch = mock(PickleStepDefinitionMatch.class); - private final CoreHookDefinition afterHookDefinition = mock(CoreHookDefinition.class); - private final HookTestStep afterHook = new HookTestStep(UUID.randomUUID(), AFTER_STEP, - new HookDefinitionMatch(afterHookDefinition)); - private final CoreHookDefinition beforeHookDefinition = mock(CoreHookDefinition.class); - private final HookTestStep beforeHook = new HookTestStep(UUID.randomUUID(), BEFORE_STEP, - new HookDefinitionMatch(beforeHookDefinition)); - private final PickleStepTestStep step = new PickleStepTestStep( - UUID.randomUUID(), - URI.create("file:path/to.feature"), - pickle.getSteps().get(0), - singletonList(beforeHook), - singletonList(afterHook), - definitionMatch); - - @BeforeEach - void init() { - Mockito.when(bus.getInstant()).thenReturn(Instant.now()); + private MockEventBus bus = new MockEventBus(); + private final TestCaseState state = new TestCaseState(bus, UUID.randomUUID(), testCase); + private PickleStepDefinitionMatch definitionMatch; + private CoreHookDefinition afterHookDefinition; + private CoreHookDefinition beforeHookDefinition; + private PickleStepTestStep step; + + private void buildStep( + RuntimeException beforeHookException, RuntimeException afterHookException, Throwable stepException + ) { + beforeHookDefinition = CoreHookDefinition.create(new MockHookDefinition(beforeHookException), UUID::randomUUID); + afterHookDefinition = CoreHookDefinition.create(new MockHookDefinition(afterHookException), UUID::randomUUID); + definitionMatch = new MockPickleStepDefinitionMatch(stepException); + step = new PickleStepTestStep( + UUID.randomUUID(), + URI.create("file:path/to.feature"), + pickle.getSteps().get(0), + singletonList(new HookTestStep(UUID.randomUUID(), BEFORE_STEP, + new HookDefinitionMatch(beforeHookDefinition))), + singletonList(new HookTestStep(UUID.randomUUID(), AFTER_STEP, + new HookDefinitionMatch(afterHookDefinition))), + definitionMatch); } @Test void run_wraps_run_step_in_test_step_started_and_finished_events() throws Throwable { + buildStep(null, null, null); + step.run(testCase, bus, state, ExecutionMode.RUN); - InOrder order = inOrder(bus, definitionMatch); - order.verify(bus).send(isA(TestStepStarted.class)); - order.verify(definitionMatch).runStep(state); - order.verify(bus).send(isA(TestStepFinished.class)); + List events = bus.events.stream() + .filter(event -> !(event instanceof Envelope)) + .collect(Collectors.toList()); + assertInstanceOf(TestStepStarted.class, events.get(0)); + Object stepDefinitionEvent = events.get(3); + assertInstanceOf(PickleStepDefinitionMatchEvent.class, stepDefinitionEvent); + assertEquals("runStep", ((PickleStepDefinitionMatchEvent) stepDefinitionEvent).method); + assertEquals(state, ((PickleStepDefinitionMatchEvent) stepDefinitionEvent).state); + assertInstanceOf(TestStepFinished.class, events.get(events.size() - 1)); } @Test void run_does_dry_run_step_when_dry_run_steps_is_true() throws Throwable { - step.run(testCase, bus, state, ExecutionMode.DRY_RUN); - - InOrder order = inOrder(bus, definitionMatch); - order.verify(bus).send(isA(TestStepStarted.class)); - order.verify(definitionMatch).dryRunStep(state); - order.verify(bus).send(isA(TestStepFinished.class)); - } + buildStep(null, null, null); - @Test - void run_skips_step_when_dry_run_and_skip_step_is_true() throws Throwable { - step.run(testCase, bus, state, ExecutionMode.SKIP); + step.run(testCase, bus, state, ExecutionMode.DRY_RUN); - InOrder order = inOrder(bus, definitionMatch); - order.verify(bus).send(isA(TestStepStarted.class)); - order.verify(definitionMatch, never()).dryRunStep(state); - order.verify(bus).send(isA(TestStepFinished.class)); + List events = bus.events.stream() + .filter(event -> !(event instanceof Envelope)) + .collect(Collectors.toList()); + assertInstanceOf(TestStepStarted.class, events.get(0)); + Object stepDefinitionEvent = events.get(3); + assertInstanceOf(PickleStepDefinitionMatchEvent.class, stepDefinitionEvent); + assertEquals("dryRunStep", ((PickleStepDefinitionMatchEvent) stepDefinitionEvent).method); + assertEquals(state, ((PickleStepDefinitionMatchEvent) stepDefinitionEvent).state); + assertInstanceOf(TestStepFinished.class, events.get(events.size() - 1)); } @Test void run_skips_step_when_skip_step_is_true() throws Throwable { + buildStep(null, null, null); + step.run(testCase, bus, state, ExecutionMode.SKIP); - InOrder order = inOrder(bus, definitionMatch); - order.verify(bus).send(isA(TestStepStarted.class)); - order.verify(definitionMatch, never()).dryRunStep(state); - order.verify(bus).send(isA(TestStepFinished.class)); + List events = bus.events.stream() + .filter(event -> !(event instanceof Envelope)) + .collect(Collectors.toList()); + assertInstanceOf(TestStepStarted.class, events.get(0)); + assertFalse(bus.events.stream().anyMatch(event -> event instanceof PickleStepDefinitionMatchEvent)); + assertInstanceOf(TestStepFinished.class, events.get(events.size() - 1)); } @Test void result_is_passed_run_when_step_definition_does_not_throw_exception() { + buildStep(null, null, null); + ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); + assertThat(nextExecutionMode, is(ExecutionMode.RUN)); assertThat(state.getStatus(), is(equalTo(PASSED))); } @Test void result_is_skipped_when_skip_step_is_not_run_all() { + buildStep(null, null, null); + ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.SKIP); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(SKIPPED))); } @Test void result_is_skipped_when_before_step_hook_does_not_pass() { - doThrow(TestAbortedException.class).when(beforeHookDefinition).execute(any(TestCaseState.class)); + buildStep(new TestAbortedException(), null, null); + ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(SKIPPED))); } @Test void step_execution_is_skipped_when_before_step_hook_does_not_pass() throws Throwable { - doThrow(TestAbortedException.class).when(beforeHookDefinition).execute(any(TestCaseState.class)); + buildStep(new TestAbortedException(), null, null); + step.run(testCase, bus, state, ExecutionMode.RUN); - verify(definitionMatch, never()).runStep(any(TestCaseState.class)); - verify(definitionMatch, never()).dryRunStep(any(TestCaseState.class)); + + assertFalse(bus.events.stream().anyMatch(event -> event instanceof PickleStepDefinitionMatchEvent)); } @Test void result_is_result_from_hook_when_before_step_hook_does_not_pass() { - Exception exception = new RuntimeException(); - doThrow(exception).when(beforeHookDefinition).execute(any(TestCaseState.class)); - Result failure = new Result(Status.FAILED, ZERO, exception); + RuntimeException exception = new RuntimeException(); + buildStep(exception, null, null); + ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(FAILED))); - - ArgumentCaptor captor = forClass(TestCaseEvent.class); - verify(bus, times(6)).send(captor.capture()); - List allValues = captor.getAllValues(); - assertThat(((TestStepFinished) allValues.get(1)).getResult(), is(equalTo(failure))); + List events = bus.events.stream() + .filter(event -> event instanceof TestCaseEvent) + .map(event -> (TestCaseEvent) event) + .collect(Collectors.toList()); + assertEquals(6, events.size()); + Result result = ((TestStepFinished) events.get(1)).getResult(); + assertEquals(Status.FAILED, result.getStatus()); + assertEquals(exception, result.getError()); } @Test void result_is_result_from_step_when_step_hook_does_not_pass() throws Throwable { RuntimeException runtimeException = new RuntimeException(); - Result failure = new Result(Status.FAILED, ZERO, runtimeException); - doThrow(runtimeException).when(definitionMatch).runStep(any(TestCaseState.class)); + buildStep(null, null, runtimeException); + ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(FAILED))); - - ArgumentCaptor captor = forClass(TestCaseEvent.class); - verify(bus, times(6)).send(captor.capture()); - List allValues = captor.getAllValues(); - assertThat(((TestStepFinished) allValues.get(3)).getResult(), is(equalTo(failure))); + List events = bus.events.stream() + .filter(event -> event instanceof TestCaseEvent) + .map(event -> (TestCaseEvent) event) + .collect(Collectors.toList()); + assertEquals(6, events.size()); + Result result = ((TestStepFinished) events.get(3)).getResult(); + assertEquals(Status.FAILED, result.getStatus()); + assertEquals(runtimeException, result.getError()); } @Test void result_is_result_from_hook_when_after_step_hook_does_not_pass() { - Exception exception = new RuntimeException(); - Result failure = new Result(Status.FAILED, ZERO, exception); - doThrow(exception).when(afterHookDefinition).execute(any(TestCaseState.class)); + RuntimeException exception = new RuntimeException(); + buildStep(null, exception, null); + ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(FAILED))); - - ArgumentCaptor captor = forClass(TestCaseEvent.class); - verify(bus, times(6)).send(captor.capture()); - List allValues = captor.getAllValues(); - assertThat(((TestStepFinished) allValues.get(5)).getResult(), is(equalTo(failure))); + List events = bus.events.stream() + .filter(event -> event instanceof TestCaseEvent) + .map(event -> (TestCaseEvent) event) + .collect(Collectors.toList()); + assertEquals(6, events.size()); + Result result = ((TestStepFinished) events.get(5)).getResult(); + assertEquals(Status.FAILED, result.getStatus()); + assertEquals(exception, result.getError()); } @Test void after_step_hook_is_run_when_before_step_hook_does_not_pass() { - doThrow(RuntimeException.class).when(beforeHookDefinition).execute(any(TestCaseState.class)); + buildStep(new RuntimeException(), null, null); + step.run(testCase, bus, state, ExecutionMode.RUN); - verify(afterHookDefinition).execute(any(TestCaseState.class)); + + assertTrue(((MockHookDefinition) afterHookDefinition.delegate).executed); } @Test void after_step_hook_is_run_when_step_does_not_pass() throws Throwable { - doThrow(Exception.class).when(definitionMatch).runStep(any(TestCaseState.class)); + buildStep(null, null, new Exception()); + step.run(testCase, bus, state, ExecutionMode.RUN); - verify(afterHookDefinition).execute(any(TestCaseState.class)); + + assertTrue(((MockHookDefinition) afterHookDefinition.delegate).executed); } @Test void after_step_hook_scenario_contains_step_failure_when_step_does_not_pass() throws Throwable { Throwable expectedError = new TestAbortedException("oops"); - doThrow(expectedError).when(definitionMatch).runStep(any(TestCaseState.class)); - doThrow(new RuntimeException()).when(afterHookDefinition).execute(argThat(scenarioDoesNotHave(expectedError))); + buildStep(null, null, expectedError); + step.run(testCase, bus, state, ExecutionMode.RUN); - assertThat(state.getError(), is(expectedError)); - } - private static ArgumentMatcher scenarioDoesNotHave(final Throwable type) { - return argument -> !type.equals(argument.getError()); + assertThat(((MockHookDefinition) afterHookDefinition.delegate).receivedError, is(expectedError)); } @Test void after_step_hook_scenario_contains_before_step_hook_failure_when_before_step_hook_does_not_pass() { - Throwable expectedError = new TestAbortedException("oops"); - doThrow(expectedError).when(beforeHookDefinition).execute(any(TestCaseState.class)); - doThrow(new RuntimeException()).when(afterHookDefinition).execute(argThat(scenarioDoesNotHave(expectedError))); + RuntimeException expectedError = new TestAbortedException("oops"); + buildStep(expectedError, null, null); + step.run(testCase, bus, state, ExecutionMode.RUN); - assertThat(state.getError(), is(expectedError)); + + assertThat(((MockHookDefinition) afterHookDefinition.delegate).receivedError, is(expectedError)); } @Test void result_is_skipped_when_step_definition_throws_assumption_violated_exception() throws Throwable { - doThrow(TestAbortedException.class).when(definitionMatch).runStep(any()); + buildStep(null, null, new TestAbortedException()); ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); - assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(SKIPPED))); } @Test void result_is_failed_when_step_definition_throws_exception() throws Throwable { - doThrow(RuntimeException.class).when(definitionMatch).runStep(any(TestCaseState.class)); + buildStep(null, null, new RuntimeException()); ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); - assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(FAILED))); } @Test void result_is_pending_when_step_definition_throws_pending_exception() throws Throwable { - doThrow(StubPendingException.class).when(definitionMatch).runStep(any(TestCaseState.class)); + buildStep(null, null, new StubPendingException()); ExecutionMode nextExecutionMode = step.run(testCase, bus, state, ExecutionMode.RUN); - assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); + assertThat(nextExecutionMode, is(ExecutionMode.SKIP)); assertThat(state.getStatus(), is(equalTo(PENDING))); } @@ -269,26 +296,142 @@ void step_execution_time_is_measured() { "Feature: Test feature\n" + " Scenario: Test scenario\n" + " Given I have 4 cukes in my belly\n"); - TestStep step = new PickleStepTestStep( UUID.randomUUID(), URI.create("file:path/to.feature"), feature.getPickles().get(0).getSteps().get(0), definitionMatch); - when(bus.getInstant()).thenReturn(ofEpochMilli(234L), ofEpochMilli(1234L)); - step.run(testCase, bus, state, ExecutionMode.RUN); - - ArgumentCaptor captor = forClass(TestCaseEvent.class); - verify(bus, times(2)).send(captor.capture()); + bus = new MockEventBus(ofEpochMilli(234L), ofEpochMilli(1234L)); - List allValues = captor.getAllValues(); - TestStepStarted started = (TestStepStarted) allValues.get(0); - TestStepFinished finished = (TestStepFinished) allValues.get(1); + step.run(testCase, bus, state, ExecutionMode.RUN); + List events = bus.events.stream() + .filter(event -> event instanceof TestCaseEvent) + .map(event -> (TestCaseEvent) event) + .collect(Collectors.toList()); + assertEquals(2, events.size()); + TestStepStarted started = (TestStepStarted) events.get(0); + TestStepFinished finished = (TestStepFinished) events.get(1); assertAll( () -> assertThat(started.getInstant(), is(equalTo(ofEpochMilli(234L)))), () -> assertThat(finished.getInstant(), is(equalTo(ofEpochMilli(1234L)))), () -> assertThat(finished.getResult().getDuration(), is(equalTo(ofMillis(1000L))))); } + private static class MockEventBus implements EventBus { + final List events = new ArrayList<>(); + final Queue instants; + + public MockEventBus(Instant... instants) { + this.instants = new ArrayDeque<>(Arrays.asList(instants)); + } + + @Override + public Instant getInstant() { + Instant instant = instants.poll(); + return instant != null ? instant : Instant.now(); + } + + @Override + public UUID generateId() { + return null; + } + + @Override + public void send(T event) { + events.add(event); + } + + @Override + public void sendAll(Iterable queue) { + queue.forEach(events::add); + } + + @Override + public void registerHandlerFor(Class eventType, EventHandler handler) { + + } + + @Override + public void removeHandlerFor(Class eventType, EventHandler handler) { + + } + } + + private static class PickleStepDefinitionMatchEvent { + Object target; + String method; + io.cucumber.core.backend.TestCaseState state; + public PickleStepDefinitionMatchEvent( + Object target, String method, io.cucumber.core.backend.TestCaseState state + ) { + this.target = target; + this.method = method; + this.state = state; + } + } + + private class MockPickleStepDefinitionMatch extends PickleStepDefinitionMatch { + private final Throwable stepException; + + MockPickleStepDefinitionMatch(Throwable stepException) { + super(new ArrayList<>(), new StubStepDefinition(""), null, null); + this.stepException = stepException; + } + + @Override + public void runStep(io.cucumber.core.backend.TestCaseState state) throws Throwable { + bus.send(new PickleStepDefinitionMatchEvent(this, "runStep", state)); + if (stepException != null) { + throw stepException; + } + } + + @Override + public void dryRunStep(io.cucumber.core.backend.TestCaseState state) throws Throwable { + bus.send(new PickleStepDefinitionMatchEvent(this, "dryRunStep", state)); + if (stepException != null) { + throw stepException; + } + } + } + + private static class MockHookDefinition implements HookDefinition { + private final RuntimeException executeException; + boolean executed; + Throwable receivedError; + + public MockHookDefinition(RuntimeException executeException) { + this.executeException = executeException; + } + + @Override + public void execute(io.cucumber.core.backend.TestCaseState state) { + executed = true; + receivedError = ((TestCaseState) state).getError(); + if (executeException != null) { + throw executeException; + } + } + + @Override + public String getTagExpression() { + return ""; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return null; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/RunnerTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/RunnerTest.java index 33b555db97..264e77a8bd 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/RunnerTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/RunnerTest.java @@ -4,6 +4,7 @@ import io.cucumber.core.backend.Glue; import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.ObjectFactory; +import io.cucumber.core.backend.Snippet; import io.cucumber.core.backend.StaticHookDefinition; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.feature.TestFeatureParser; @@ -14,11 +15,11 @@ import io.cucumber.core.runtime.TimeServiceEventBus; import io.cucumber.core.snippets.TestSnippet; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; import java.net.URI; import java.time.Clock; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -28,53 +29,33 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertTrue; class RunnerTest { private final RuntimeOptions runtimeOptions = RuntimeOptions.defaultOptions(); private final EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); - @Test void hooks_execute_inside_world_and_around_world() { - StaticHookDefinition beforeAllHook = createStaticHook(); - StaticHookDefinition afterAllHook = createStaticHook(); - HookDefinition beforeHook = createHook(); - HookDefinition afterHook = createHook(); - - Backend backend = mock(Backend.class); - when(backend.getSnippet()).thenReturn(new TestSnippet()); - ObjectFactory objectFactory = mock(ObjectFactory.class); - doAnswer(invocation -> { - Glue glue = invocation.getArgument(0); - glue.addBeforeAllHook(beforeAllHook); - glue.addAfterAllHook(afterAllHook); - glue.addBeforeHook(beforeHook); - glue.addAfterHook(afterHook); - return null; - }).when(backend).loadGlue(any(Glue.class), ArgumentMatchers.anyList()); + List listener = new ArrayList<>(); + StaticHookDefinition beforeAllHook = new MockStaticHookDefinition("beforeAllHook", listener); + StaticHookDefinition afterAllHook = new MockStaticHookDefinition("afterAllHook", listener); + HookDefinition beforeHook = new MockHookDefinition("beforeHook", listener); + HookDefinition afterHook = new MockHookDefinition("afterHook", listener); + + Backend backend = new MockBackend(beforeAllHook, afterAllHook, beforeHook, afterHook, listener); + ObjectFactory objectFactory = new MockObjectFactory(); Runner runner = new Runner(bus, singletonList(backend), objectFactory, runtimeOptions); runner.runBeforeAllHooks(); runner.runPickle(createPicklesWithSteps()); runner.runAfterAllHooks(); - InOrder inOrder = inOrder(beforeAllHook, afterAllHook, beforeHook, afterHook, backend); - inOrder.verify(beforeAllHook).execute(); - inOrder.verify(backend).buildWorld(); - inOrder.verify(beforeHook).execute(any(TestCaseState.class)); - inOrder.verify(afterHook).execute(any(TestCaseState.class)); - inOrder.verify(backend).disposeWorld(); - inOrder.verify(afterAllHook).execute(); + assertLinesMatch( + List.of("beforeAllHook", "buildWorld", "beforeHook", "afterHook", "disposeWorld", "afterAllHook"), + listener); } private Pickle createPicklesWithSteps() { @@ -85,26 +66,14 @@ private Pickle createPicklesWithSteps() { return feature.getPickles().get(0); } - private StaticHookDefinition createStaticHook() { - StaticHookDefinition hook = mock(StaticHookDefinition.class); - when(hook.getLocation()).thenReturn(""); - return hook; - } - - private HookDefinition createHook() { - HookDefinition hook = mock(HookDefinition.class); - when(hook.getTagExpression()).thenReturn(""); - when(hook.getLocation()).thenReturn(""); - return hook; - } - @Test void steps_are_skipped_after_failure() { - StubStepDefinition stepDefinition = spy(new StubStepDefinition("some step")); + List listener = new ArrayList<>(); + StubStepDefinition stepDefinition = new MockStubStepDefinition(listener); Pickle pickleMatchingStepDefinitions = createPickleMatchingStepDefinitions(stepDefinition); - final HookDefinition failingBeforeHook = createHook(); - doThrow(new RuntimeException("Boom")).when(failingBeforeHook).execute(ArgumentMatchers.any()); + final HookDefinition failingBeforeHook = new MockHookDefinition("beforeHook", listener, + new RuntimeException("Boom")); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override public void loadGlue(Glue glue, List gluePaths) { @@ -115,9 +84,7 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickleMatchingStepDefinitions); - InOrder inOrder = inOrder(failingBeforeHook, stepDefinition); - inOrder.verify(failingBeforeHook).execute(any(TestCaseState.class)); - inOrder.verify(stepDefinition, never()).execute(any(Object[].class)); + assertLinesMatch(List.of("beforeHook"), listener); } private Pickle createPickleMatchingStepDefinitions(StubStepDefinition stepDefinition) { @@ -131,18 +98,11 @@ private Pickle createPickleMatchingStepDefinitions(StubStepDefinition stepDefini @Test void aftersteps_are_executed_after_failed_step() { - StubStepDefinition stepDefinition = spy(new StubStepDefinition("some step") { - - @Override - public void execute(Object[] args) { - super.execute(args); - throw new RuntimeException(); - } - }); - + List listener = new ArrayList<>(); + StubStepDefinition stepDefinition = new MockStubStepDefinition(listener, new RuntimeException()); Pickle pickleMatchingStepDefinitions = createPickleMatchingStepDefinitions(stepDefinition); - final HookDefinition afterStepHook = createHook(); + final HookDefinition afterStepHook = new MockHookDefinition("afterHook", listener); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -154,18 +114,17 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickleMatchingStepDefinitions); - InOrder inOrder = inOrder(afterStepHook, stepDefinition); - inOrder.verify(stepDefinition).execute(any(Object[].class)); - inOrder.verify(afterStepHook).execute(any(TestCaseState.class)); + assertLinesMatch(List.of("stepDefinition", "afterHook"), listener); } @Test void aftersteps_executed_for_passed_step() { - StubStepDefinition stepDefinition = spy(new StubStepDefinition("some step")); + List listener = new ArrayList<>(); + StubStepDefinition stepDefinition = new MockStubStepDefinition(listener); Pickle pickle = createPickleMatchingStepDefinitions(stepDefinition); - HookDefinition afteStepHook1 = createHook(); - HookDefinition afteStepHook2 = createHook(); + HookDefinition afteStepHook1 = new MockHookDefinition("afterHook1", listener); + HookDefinition afteStepHook2 = new MockHookDefinition("afterHook2", listener); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -178,19 +137,18 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(pickle); - InOrder inOrder = inOrder(afteStepHook1, afteStepHook2, stepDefinition); - inOrder.verify(stepDefinition).execute(any(Object[].class)); - inOrder.verify(afteStepHook2).execute(any(TestCaseState.class)); - inOrder.verify(afteStepHook1).execute(any(TestCaseState.class)); + assertLinesMatch(List.of("stepDefinition", "afterHook2", "afterHook1"), listener); } @Test void hooks_execute_also_after_failure() { - HookDefinition beforeHook = createHook(); - HookDefinition afterHook = createHook(); + List listener = new ArrayList<>(); + HookDefinition beforeHook = new MockHookDefinition("beforeHook", listener); + HookDefinition afterHook = new MockHookDefinition("afterHook", listener); + ; - HookDefinition failingBeforeHook = createHook(); - doThrow(new RuntimeException("boom")).when(failingBeforeHook).execute(any(TestCaseState.class)); + HookDefinition failingBeforeHook = new MockHookDefinition("failingBeforeHook", listener, + new RuntimeException("boom")); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -203,17 +161,15 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(createPicklesWithSteps()); - InOrder inOrder = inOrder(failingBeforeHook, beforeHook, afterHook); - inOrder.verify(failingBeforeHook).execute(any(TestCaseState.class)); - inOrder.verify(beforeHook).execute(any(TestCaseState.class)); - inOrder.verify(afterHook).execute(any(TestCaseState.class)); + assertLinesMatch(List.of("failingBeforeHook", "beforeHook", "afterHook"), listener); } @Test void all_static_hooks_execute_also_after_failure() { - StaticHookDefinition beforeAllHook = createStaticHook(); - StaticHookDefinition failingBeforeAllHook = createStaticHook(); - doThrow(new RuntimeException("boom")).when(failingBeforeAllHook).execute(); + List listener = new ArrayList<>(); + StaticHookDefinition beforeAllHook = new MockStaticHookDefinition("beforeAllHook", listener); + StaticHookDefinition failingBeforeAllHook = new MockStaticHookDefinition("failingBeforeAllHook", listener, + new RuntimeException("boom")); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @Override @@ -226,9 +182,7 @@ public void loadGlue(Glue glue, List gluePaths) { Runner runner = runnerSupplier.get(); assertThrows(RuntimeException.class, runner::runBeforeAllHooks); - InOrder inOrder = inOrder(beforeAllHook, failingBeforeAllHook); - inOrder.verify(beforeAllHook).execute(); - inOrder.verify(failingBeforeAllHook).execute(); + assertLinesMatch(List.of("beforeAllHook", "failingBeforeAllHook"), listener); } @Test @@ -265,12 +219,13 @@ public void loadGlue(Glue glue, List gluePaths) { void hooks_not_executed_in_dry_run_mode() { RuntimeOptions runtimeOptions = new RuntimeOptionsBuilder().setDryRun().build(); - StaticHookDefinition beforeAllHook = createStaticHook(); - StaticHookDefinition afterAllHook = createStaticHook(); - HookDefinition beforeHook = createHook(); - HookDefinition afterHook = createHook(); - HookDefinition beforeStepHook = createHook(); - HookDefinition afterStepHook = createHook(); + List listener = new ArrayList<>(); + StaticHookDefinition beforeAllHook = new MockStaticHookDefinition("beforeAllHook", listener); + StaticHookDefinition afterAllHook = new MockStaticHookDefinition("afterAllHook", listener); + HookDefinition beforeHook = new MockHookDefinition("beforeHook", listener); + HookDefinition afterHook = new MockHookDefinition("afterHook", listener); + HookDefinition beforeStepHook = new MockHookDefinition("beforeStepHook", listener); + HookDefinition afterStepHook = new MockHookDefinition("afterStepHook", listener); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @@ -288,20 +243,16 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(createPicklesWithSteps()); runnerSupplier.get().runAfterAllHooks(); - verify(beforeAllHook, never()).execute(); - verify(afterAllHook, never()).execute(); - verify(beforeHook, never()).execute(any(TestCaseState.class)); - verify(afterHook, never()).execute(any(TestCaseState.class)); - verify(beforeStepHook, never()).execute(any(TestCaseState.class)); - verify(afterStepHook, never()).execute(any(TestCaseState.class)); + assertLinesMatch(Collections.emptyList(), listener); } @Test void scenario_hooks_not_executed_for_empty_pickles() { - HookDefinition beforeHook = createHook(); - HookDefinition afterHook = createHook(); - HookDefinition beforeStepHook = createHook(); - HookDefinition afterStepHook = createHook(); + List listener = new ArrayList<>(); + HookDefinition beforeHook = new MockHookDefinition("beforeHook", listener); + HookDefinition afterHook = new MockHookDefinition("afterHook", listener); + HookDefinition beforeStepHook = new MockHookDefinition("beforeStepHook", listener); + HookDefinition afterStepHook = new MockHookDefinition("afterStepHook", listener); TestRunnerSupplier runnerSupplier = new TestRunnerSupplier(bus, runtimeOptions) { @@ -316,9 +267,7 @@ public void loadGlue(Glue glue, List gluePaths) { runnerSupplier.get().runPickle(createEmptyPickle()); - verify(beforeHook, never()).execute(any(TestCaseState.class)); - verify(afterStepHook, never()).execute(any(TestCaseState.class)); - verify(afterHook, never()).execute(any(TestCaseState.class)); + assertLinesMatch(Collections.emptyList(), listener); } private Pickle createEmptyPickle() { @@ -330,12 +279,192 @@ private Pickle createEmptyPickle() { @Test void backends_are_asked_for_snippets_for_undefined_steps() { - Backend backend = mock(Backend.class); - when(backend.getSnippet()).thenReturn(new TestSnippet()); - ObjectFactory objectFactory = mock(ObjectFactory.class); + List listener = new ArrayList<>(); + MockBackend backend = new MockBackend(null, null, null, null, listener); + ObjectFactory objectFactory = new MockObjectFactory(); Runner runner = new Runner(bus, singletonList(backend), objectFactory, runtimeOptions); runner.runPickle(createPicklesWithSteps()); - verify(backend).getSnippet(); + assertTrue(backend.getSnippetCalled); + } + + private static class MockBackend implements Backend { + private final StaticHookDefinition beforeAllHook; + private final StaticHookDefinition afterAllHook; + private final HookDefinition beforeHook; + private final HookDefinition afterHook; + private final List listener; + boolean getSnippetCalled; + + public MockBackend( + StaticHookDefinition beforeAllHook, StaticHookDefinition afterAllHook, + HookDefinition beforeHook, HookDefinition afterHook, List listener + ) { + this.beforeAllHook = beforeAllHook; + this.afterAllHook = afterAllHook; + this.beforeHook = beforeHook; + this.afterHook = afterHook; + this.listener = listener; + } + + @Override + public void loadGlue(Glue glue, List gluePaths) { + if (beforeAllHook != null) { + glue.addBeforeAllHook(beforeAllHook); + } + if (afterAllHook != null) { + glue.addAfterAllHook(afterAllHook); + } + if (beforeHook != null) { + glue.addBeforeHook(beforeHook); + } + if (afterHook != null) { + glue.addAfterHook(afterHook); + } + } + + @Override + public void buildWorld() { + listener.add("buildWorld"); + } + + @Override + public void disposeWorld() { + listener.add("disposeWorld"); + } + + @Override + public Snippet getSnippet() { + getSnippetCalled = true; + return new TestSnippet(); + } + } + + private static class MockObjectFactory implements ObjectFactory { + @Override + public boolean addClass(Class glueClass) { + return false; + } + + @Override + public T getInstance(Class glueClass) { + return null; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } } + private static class MockStaticHookDefinition implements StaticHookDefinition { + private final String hookName; + private final List listener; + private final RuntimeException exception; + + public MockStaticHookDefinition(String hookName, List listener) { + this(hookName, listener, null); + } + + public MockStaticHookDefinition(String hookName, List listener, RuntimeException exception) { + this.hookName = hookName; + this.listener = listener; + this.exception = exception; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return ""; + } + + @Override + public void execute() { + listener.add(hookName); + if (exception != null) { + throw exception; + } + } + + @Override + public int getOrder() { + return 0; + } + } + + private static class MockHookDefinition implements HookDefinition { + private final String hookName; + private final List listener; + private final RuntimeException exception; + + public MockHookDefinition(String hookName, List listener) { + this(hookName, listener, null); + } + + public MockHookDefinition(String hookName, List listener, RuntimeException exception) { + this.hookName = hookName; + this.listener = listener; + this.exception = exception; + } + + @Override + public void execute(io.cucumber.core.backend.TestCaseState state) { + listener.add(hookName); + if (exception != null) { + throw exception; + } + } + + @Override + public String getTagExpression() { + return ""; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return ""; + } + } + + private static class MockStubStepDefinition extends StubStepDefinition { + private final List listener; + private final RuntimeException exception; + + MockStubStepDefinition(List listener) { + this(listener, null); + } + + MockStubStepDefinition(List listener, RuntimeException exception) { + super("some step"); + this.listener = listener; + this.exception = exception; + } + + @Override + public void execute(Object[] args) { + super.execute(args); + listener.add("stepDefinition"); + if (exception != null) { + throw exception; + } + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/StubEventBus.java b/cucumber-core/src/test/java/io/cucumber/core/runner/StubEventBus.java new file mode 100644 index 0000000000..fe26feab9b --- /dev/null +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/StubEventBus.java @@ -0,0 +1,39 @@ +package io.cucumber.core.runner; + +import io.cucumber.core.eventbus.EventBus; +import io.cucumber.plugin.event.EventHandler; + +import java.time.Instant; +import java.util.UUID; + +public class StubEventBus implements EventBus { + @Override + public Instant getInstant() { + return null; + } + + @Override + public UUID generateId() { + return null; + } + + @Override + public void send(T event) { + + } + + @Override + public void sendAll(Iterable queue) { + + } + + @Override + public void registerHandlerFor(Class eventType, EventHandler handler) { + + } + + @Override + public void removeHandlerFor(Class eventType, EventHandler handler) { + + } +} diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java index f1082fe48e..c74101a68b 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java @@ -4,16 +4,17 @@ import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; import io.cucumber.plugin.event.EmbedEvent; +import io.cucumber.plugin.event.EventHandler; import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.Status; import io.cucumber.plugin.event.WriteEvent; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; import java.time.Instant; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.UUID; import static io.cucumber.core.backend.Status.FAILED; @@ -26,12 +27,10 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; class TestCaseStateResultTest { @@ -39,7 +38,7 @@ class TestCaseStateResultTest { "Feature: Test feature\n" + " Scenario: Test scenario\n" + " Given I have 4 cukes in my belly\n"); - private final EventBus bus = mock(EventBus.class); + private final MockEventBus bus = new MockEventBus(); private final TestCaseState s = new TestCaseState( bus, UUID.randomUUID(), @@ -53,7 +52,6 @@ class TestCaseStateResultTest { @BeforeEach void setup() { - when(bus.getInstant()).thenReturn(Instant.now()); s.setCurrentTestStepId(UUID.randomUUID()); } @@ -117,21 +115,28 @@ void passed_undefined_skipped_is_undefined() { @SuppressWarnings("deprecation") @Test void embeds_data() { + bus.events.clear(); byte[] data = new byte[] { 1, 2, 3 }; + s.attach(data, "bytes/foo", null); - verify(bus).send(argThat(new EmbedEventMatcher(data, "bytes/foo"))); + + assertInstanceOf(EmbedEvent.class, bus.events.get(0)); + assertEquals("bytes/foo", ((EmbedEvent) bus.events.get(0)).getMediaType()); + assertEquals(data, ((EmbedEvent) bus.events.get(0)).getData()); } @Test void prints_output() { + bus.events.clear(); s.log("Hi"); - verify(bus).send(argThat(new WriteEventMatcher("Hi"))); + assertInstanceOf(WriteEvent.class, bus.events.get(0)); + assertEquals("Hi", ((WriteEvent) bus.events.get(0)).getText()); } @Test void failed_followed_by_pending_yields_failed_error() { - Throwable failedError = mock(Throwable.class); - Throwable pendingError = mock(Throwable.class); + Throwable failedError = new Throwable(); + Throwable pendingError = new Throwable(); s.add(new Result(Status.FAILED, ZERO, failedError)); s.add(new Result(Status.PENDING, ZERO, pendingError)); @@ -141,8 +146,8 @@ void failed_followed_by_pending_yields_failed_error() { @Test void pending_followed_by_failed_yields_failed_error() { - Throwable pendingError = mock(Throwable.class); - Throwable failedError = mock(Throwable.class); + Throwable pendingError = new Throwable(); + Throwable failedError = new Throwable(); s.add(new Result(Status.PENDING, ZERO, pendingError)); s.add(new Result(Status.FAILED, ZERO, failedError)); @@ -150,37 +155,36 @@ void pending_followed_by_failed_yields_failed_error() { assertThat(s.getError(), sameInstance(failedError)); } - private static final class EmbedEventMatcher implements ArgumentMatcher { + private static class MockEventBus implements EventBus { + List events = new ArrayList<>(); - private final byte[] data; - private final String mediaType; - - EmbedEventMatcher(byte[] data, String mediaType) { - this.data = data; - this.mediaType = mediaType; + @Override + public Instant getInstant() { + return Instant.now(); } @Override - public boolean matches(EmbedEvent argument) { - return (argument != null && - Arrays.equals(argument.getData(), data) && argument.getMediaType().equals(mediaType)); + public UUID generateId() { + return null; } - } + @Override + public void send(T event) { + this.events.add(event); + } - private static final class WriteEventMatcher implements ArgumentMatcher { + @Override + public void sendAll(Iterable queue) { + } - private final String text; + @Override + public void registerHandlerFor(Class eventType, EventHandler handler) { - WriteEventMatcher(String text) { - this.text = text; } @Override - public boolean matches(WriteEvent argument) { - return (argument != null && argument.getText().equals(text)); - } + public void removeHandlerFor(Class eventType, EventHandler handler) { + } } - } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java index 04fd4c5676..9602068fcf 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java @@ -1,89 +1,95 @@ package io.cucumber.core.runner; +import io.cucumber.core.backend.CucumberBackendException; +import io.cucumber.core.backend.CucumberInvocationTargetException; +import io.cucumber.core.backend.HookDefinition; +import io.cucumber.core.backend.ParameterInfo; +import io.cucumber.core.backend.StepDefinition; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; import io.cucumber.core.gherkin.Pickle; +import io.cucumber.plugin.event.EventHandler; +import io.cucumber.plugin.event.Status; import io.cucumber.plugin.event.TestCaseFinished; import io.cucumber.plugin.event.TestCaseStarted; -import org.junit.jupiter.api.BeforeEach; +import io.cucumber.plugin.event.TestStepFinished; +import io.cucumber.plugin.event.TestStepStarted; import org.junit.jupiter.api.Test; -import org.mockito.InOrder; import java.net.URI; import java.time.Instant; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import static io.cucumber.plugin.event.HookType.AFTER_STEP; import static io.cucumber.plugin.event.HookType.BEFORE_STEP; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertEquals; class TestCaseTest { - private final Feature feature = TestFeatureParser.parse("" + "Feature: Test feature\n" + " Scenario: Test scenario\n" + " Given I have 4 cukes in my belly\n" + " And I have 4 cucumber on my plate\n"); - private final EventBus bus = mock(EventBus.class); - - private final PickleStepDefinitionMatch definitionMatch1 = mock(PickleStepDefinitionMatch.class); - private final CoreHookDefinition beforeStep1HookDefinition1 = mock(CoreHookDefinition.class); - private final CoreHookDefinition afterStep1HookDefinition1 = mock(CoreHookDefinition.class); - - private final PickleStepTestStep testStep1 = new PickleStepTestStep( - UUID.randomUUID(), - URI.create("file:path/to.feature"), - feature.getPickles().get(0).getSteps().get(0), - singletonList( - new HookTestStep(UUID.randomUUID(), BEFORE_STEP, new HookDefinitionMatch(beforeStep1HookDefinition1))), - singletonList( - new HookTestStep(UUID.randomUUID(), AFTER_STEP, new HookDefinitionMatch(afterStep1HookDefinition1))), - definitionMatch1); - - private final PickleStepDefinitionMatch definitionMatch2 = mock(PickleStepDefinitionMatch.class); - private final CoreHookDefinition beforeStep1HookDefinition2 = mock(CoreHookDefinition.class); - private final CoreHookDefinition afterStep1HookDefinition2 = mock(CoreHookDefinition.class); - private final PickleStepTestStep testStep2 = new PickleStepTestStep( - UUID.randomUUID(), - URI.create("file:path/to.feature"), - feature.getPickles().get(0).getSteps().get(1), - singletonList( - new HookTestStep(UUID.randomUUID(), BEFORE_STEP, new HookDefinitionMatch(beforeStep1HookDefinition2))), - singletonList( - new HookTestStep(UUID.randomUUID(), AFTER_STEP, new HookDefinitionMatch(afterStep1HookDefinition2))), - definitionMatch2); - - @BeforeEach - void init() { - when(bus.getInstant()).thenReturn(Instant.now()); - when(bus.generateId()).thenReturn(UUID.randomUUID()); - - when(beforeStep1HookDefinition1.getId()).thenReturn(UUID.randomUUID()); - when(beforeStep1HookDefinition2.getId()).thenReturn(UUID.randomUUID()); - when(afterStep1HookDefinition1.getId()).thenReturn(UUID.randomUUID()); - when(afterStep1HookDefinition2.getId()).thenReturn(UUID.randomUUID()); + private final PickleStepTestStep testStep1 = createPickleStepTestStep(0, + new PickleStepDefinitionMatch(Collections.emptyList(), + new StubStepDefinition(), + null, + null)); + + private final PickleStepTestStep testStep2 = createPickleStepTestStep(1, + new PickleStepDefinitionMatch(Collections.emptyList(), + new StubStepDefinition(), + null, + null)); + + private final PickleStepTestStep testStepUndefined = createPickleStepTestStep(0, + new UndefinedPickleStepDefinitionMatch(null, null)); + + private PickleStepTestStep createPickleStepTestStep(int index, PickleStepDefinitionMatch definitionMatch) { + return new PickleStepTestStep( + UUID.randomUUID(), + URI.create("file:path/to.feature"), + feature.getPickles().get(0).getSteps().get(index), + singletonList( + new HookTestStep(UUID.randomUUID(), BEFORE_STEP, + new HookDefinitionMatch(CoreHookDefinition.create(new StubHookDefinition(), UUID::randomUUID)))), + singletonList( + new HookTestStep(UUID.randomUUID(), AFTER_STEP, + new HookDefinitionMatch(CoreHookDefinition.create(new StubHookDefinition(), UUID::randomUUID)))), + definitionMatch); } @Test - void run_wraps_execute_in_test_case_started_and_finished_events() throws Throwable { - doThrow(new UndefinedStepDefinitionException()).when(definitionMatch1).runStep(isA(TestCaseState.class)); + void run_wraps_execute_in_test_case_started_and_finished_events() { + // Given + MockEventBus bus = new MockEventBus(); - createTestCase(testStep1).run(bus); + // When + createTestCase(testStepUndefined).run(bus); - InOrder order = inOrder(bus, definitionMatch1); - order.verify(bus).send(isA(TestCaseStarted.class)); - order.verify(definitionMatch1).runStep(isA(TestCaseState.class)); - order.verify(bus).send(isA(TestCaseFinished.class)); + // Then + List events = bus.events.stream() + .filter(event -> event instanceof TestCaseStarted || + event instanceof TestStepFinished || + event instanceof TestCaseFinished) + .collect(Collectors.toList()); + assertEquals(5, events.size()); + assertEquals(TestCaseStarted.class, events.get(0).getClass()); + assertEquals(TestStepFinished.class, events.get(1).getClass()); // before + // hook + assertEquals(TestStepFinished.class, events.get(2).getClass()); // undefined + // step + assertEquals(TestStepFinished.class, events.get(3).getClass()); // after + // hook + assertEquals(TestCaseFinished.class, events.get(4).getClass()); } private TestCase createTestCase(PickleStepTestStep... steps) { @@ -100,53 +106,159 @@ private Pickle pickle() { } @Test - void run_all_steps() throws Throwable { + void run_all_steps() { + // Given + MockEventBus bus = new MockEventBus(); TestCase testCase = createTestCase(testStep1, testStep2); + + // When testCase.run(bus); - InOrder order = inOrder(definitionMatch1, definitionMatch2); - order.verify(definitionMatch1).runStep(isA(TestCaseState.class)); - order.verify(definitionMatch2).runStep(isA(TestCaseState.class)); + // Then + List testStepsStarted = bus.events.stream() + .filter(event -> event instanceof TestStepStarted) + .map(event -> (TestStepStarted) event) + .filter(event -> event.getTestStep() instanceof io.cucumber.plugin.event.PickleStepTestStep) + .collect(Collectors.toList()); + assertEquals(2, testStepsStarted.size()); + // test steps are run in order + assertEquals(testStep1.getId(), testStepsStarted.get(0).getTestStep().getId()); + assertEquals(testStep2.getId(), testStepsStarted.get(1).getTestStep().getId()); } @Test - void run_hooks_after_the_first_non_passed_result_for_gherkin_step() throws Throwable { - doThrow(new UndefinedStepDefinitionException()).when(definitionMatch1).runStep(isA(TestCaseState.class)); + void run_hooks_after_the_first_non_passed_result_for_gherkin_step() { + // Given + MockEventBus bus = new MockEventBus(); + TestCase testCase = createTestCase(testStepUndefined, testStep2); - TestCase testCase = createTestCase(testStep1, testStep2); + // When testCase.run(bus); - InOrder order = inOrder(beforeStep1HookDefinition1, definitionMatch1, afterStep1HookDefinition1); - order.verify(beforeStep1HookDefinition1).execute(isA(TestCaseState.class)); - order.verify(definitionMatch1).runStep(isA(TestCaseState.class)); - order.verify(afterStep1HookDefinition1).execute(isA(TestCaseState.class)); + // Then + List testStepsFinished = bus.events.stream() + .filter(event -> event instanceof TestStepFinished) + .map(event -> (TestStepFinished) event) + .collect(Collectors.toList()); + assertEquals(testCase.getTestSteps().size(), testStepsFinished.size()); + // run_hooks_after_the_first_non_passed_result_for_gherkin_step + assertEquals(Status.PASSED, testStepsFinished.get(0).getResult().getStatus()); // before + // step1 + // hook + assertEquals(Status.UNDEFINED, testStepsFinished.get(1).getResult().getStatus()); // step + // 1 + // (undefined) + assertEquals(Status.PASSED, testStepsFinished.get(2).getResult().getStatus()); // after + // step1 + // hook + // skip_hooks_of_step_after_skipped_step + assertEquals(Status.SKIPPED, testStepsFinished.get(3).getResult().getStatus()); // before + // step2 + // hook + assertEquals(Status.SKIPPED, testStepsFinished.get(4).getResult().getStatus()); // step + // 2 + assertEquals(Status.SKIPPED, testStepsFinished.get(5).getResult().getStatus()); // after + // step2 + // hook } - @Test - void skip_hooks_of_step_after_skipped_step() throws Throwable { - doThrow(new UndefinedStepDefinitionException()).when(definitionMatch1).runStep(isA(TestCaseState.class)); + private static class MockEventBus implements EventBus { + List events = new ArrayList<>(); - TestCase testCase = createTestCase(testStep1, testStep2); - testCase.run(bus); + @Override + public Instant getInstant() { + return Instant.now(); + } - InOrder order = inOrder(beforeStep1HookDefinition2, definitionMatch2, afterStep1HookDefinition2); - order.verify(beforeStep1HookDefinition2, never()).execute(isA(TestCaseState.class)); - order.verify(definitionMatch2, never()).runStep(isA(TestCaseState.class)); - order.verify(definitionMatch2, never()).dryRunStep(isA(TestCaseState.class)); - order.verify(afterStep1HookDefinition2, never()).execute(isA(TestCaseState.class)); + @Override + public UUID generateId() { + return UUID.randomUUID(); + } + + @Override + public void send(T event) { + events.add(event); + } + + @Override + public void sendAll(Iterable queue) { + + } + + @Override + public void registerHandlerFor(Class eventType, EventHandler handler) { + + } + + @Override + public void removeHandlerFor(Class eventType, EventHandler handler) { + + } } - @Test - void skip_steps_at_first_gherkin_step_after_non_passed_result() throws Throwable { - doThrow(new UndefinedStepDefinitionException()).when(definitionMatch1).runStep(isA(TestCaseState.class)); + private static class StubStepDefinition implements StepDefinition { + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } - TestCase testCase = createTestCase(testStep1, testStep2); - testCase.run(bus); + @Override + public String getLocation() { + return null; + } + + @Override + public void execute(Object[] args) throws CucumberBackendException, CucumberInvocationTargetException { + + } - InOrder order = inOrder(definitionMatch1, definitionMatch2); - order.verify(definitionMatch1).runStep(isA(TestCaseState.class)); - order.verify(definitionMatch2, never()).dryRunStep(isA(TestCaseState.class)); - order.verify(definitionMatch2, never()).runStep(isA(TestCaseState.class)); + @Override + public List parameterInfos() { + return null; + } + + @Override + public String getPattern() { + return null; + } } + private static class StubHookDefinition implements HookDefinition { + + private final int order; + + StubHookDefinition() { + this(0); + } + + StubHookDefinition(int order) { + this.order = order; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return "mocked hook definition"; + } + + @Override + public void execute(io.cucumber.core.backend.TestCaseState state) { + + } + + @Override + public String getTagExpression() { + return ""; + } + + @Override + public int getOrder() { + return order; + } + + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/UndefinedStepDefinitionMatchTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/UndefinedStepDefinitionMatchTest.java index 44b07df985..b3f66ec9fc 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/UndefinedStepDefinitionMatchTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/UndefinedStepDefinitionMatchTest.java @@ -1,7 +1,9 @@ package io.cucumber.core.runner; +import io.cucumber.core.eventbus.IncrementingUuidGenerator; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; +import io.cucumber.core.plugin.StubTestCase; import org.junit.jupiter.api.Test; import java.net.URI; @@ -9,7 +11,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; class UndefinedStepDefinitionMatchTest { @@ -21,18 +22,19 @@ class UndefinedStepDefinitionMatchTest { private final UndefinedPickleStepDefinitionMatch match = new UndefinedPickleStepDefinitionMatch( URI.create("file:path/to.feature"), feature.getPickles().get(0).getSteps().get(0)); - + private final TestCaseState mockTestCaseState = new TestCaseState(new StubEventBus(), + new IncrementingUuidGenerator().generateId(), new StubTestCase()); @Test void throws_undefined_step_definitions_exception_when_run() { UndefinedStepDefinitionException expectedThrown = assertThrows(UndefinedStepDefinitionException.class, - () -> match.runStep(mock(TestCaseState.class))); + () -> match.runStep(mockTestCaseState)); assertThat(expectedThrown.getMessage(), equalTo("No step definitions found")); } @Test void throws_undefined_step_definitions_exception_when_dry_run() { UndefinedStepDefinitionException expectedThrown = assertThrows(UndefinedStepDefinitionException.class, - () -> match.dryRunStep(mock(TestCaseState.class))); + () -> match.dryRunStep(mockTestCaseState)); assertThat(expectedThrown.getMessage(), equalTo("No step definitions found")); } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runtime/CucumberExecutionContextTest.java b/cucumber-core/src/test/java/io/cucumber/core/runtime/CucumberExecutionContextTest.java index fb9057e9e8..25d7b8d750 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runtime/CucumberExecutionContextTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runtime/CucumberExecutionContextTest.java @@ -3,9 +3,9 @@ import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.options.RuntimeOptions; import io.cucumber.core.options.RuntimeOptionsBuilder; +import io.cucumber.core.plugin.StubTestCase; import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.Status; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestCaseFinished; import io.cucumber.plugin.event.TestRunFinished; import io.cucumber.plugin.event.TestRunStarted; @@ -24,7 +24,6 @@ import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; class CucumberExecutionContextTest { @@ -43,7 +42,7 @@ class CucumberExecutionContextTest { private final CucumberExecutionContext context = new CucumberExecutionContext(bus, exitStatus, runnerSupplier); @Test - public void collects_and_rethrows_failures_in_runner() { + void collects_and_rethrows_failures_in_runner() { IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> context.runTestCase(runner -> { throw failure; })); @@ -52,10 +51,10 @@ public void collects_and_rethrows_failures_in_runner() { } @Test - public void rethrows_but_does_not_collect_failures_in_test_case() { + void rethrows_but_does_not_collect_failures_in_test_case() { IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> context.runTestCase(runner -> { try (TestCaseResultObserver r = new TestCaseResultObserver(bus)) { - bus.send(new TestCaseFinished(bus.getInstant(), mock(TestCase.class), + bus.send(new TestCaseFinished(bus.getInstant(), new StubTestCase(), new Result(Status.FAILED, Duration.ZERO, failure))); r.assertTestCasePassed( Exception::new, @@ -69,7 +68,7 @@ public void rethrows_but_does_not_collect_failures_in_test_case() { } @Test - public void emits_failures_in_events() { + void emits_failures_in_events() { List testRunStarted = new ArrayList<>(); List testRunFinished = new ArrayList<>(); diff --git a/cucumber-core/src/test/java/io/cucumber/core/runtime/ExitStatusTest.java b/cucumber-core/src/test/java/io/cucumber/core/runtime/ExitStatusTest.java index 61eb6f92d3..426857a3c0 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runtime/ExitStatusTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runtime/ExitStatusTest.java @@ -3,9 +3,9 @@ import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.options.RuntimeOptions; import io.cucumber.core.options.RuntimeOptionsBuilder; +import io.cucumber.core.plugin.StubTestCase; import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.Status; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestCaseFinished; import org.junit.jupiter.api.Test; @@ -17,7 +17,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -import static org.mockito.Mockito.mock; class ExitStatusTest { @@ -55,7 +54,7 @@ private void createWipRuntime() { } private TestCaseFinished testCaseFinishedWithStatus(Status resultStatus) { - return new TestCaseFinished(ANY_INSTANT, mock(TestCase.class), new Result(resultStatus, ZERO, null)); + return new TestCaseFinished(ANY_INSTANT, new StubTestCase(), new Result(resultStatus, ZERO, null)); } @Test diff --git a/cucumber-core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java b/cucumber-core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java index f7167191e8..4086412259 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java @@ -6,7 +6,6 @@ import io.cucumber.core.backend.ParameterInfo; import io.cucumber.core.backend.ScenarioScoped; import io.cucumber.core.backend.StaticHookDefinition; -import io.cucumber.core.backend.StubStepDefinition; import io.cucumber.core.backend.TestCaseState; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.exception.CompositeCucumberException; @@ -15,6 +14,7 @@ import io.cucumber.core.gherkin.Feature; import io.cucumber.core.gherkin.FeatureParserException; import io.cucumber.core.options.RuntimeOptionsBuilder; +import io.cucumber.core.plugin.StubTestCase; import io.cucumber.core.runner.StepDurationTimeService; import io.cucumber.core.runner.TestBackendSupplier; import io.cucumber.messages.types.Envelope; @@ -27,7 +27,6 @@ import io.cucumber.plugin.event.Status; import io.cucumber.plugin.event.StepDefinedEvent; import io.cucumber.plugin.event.StepDefinition; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestCaseFinished; import io.cucumber.plugin.event.TestCaseStarted; import io.cucumber.plugin.event.TestRunFinished; @@ -36,7 +35,6 @@ import io.cucumber.plugin.event.TestStepStarted; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; -import org.mockito.ArgumentCaptor; import java.net.URI; import java.time.Clock; @@ -60,10 +58,8 @@ import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; class RuntimeTest { @@ -89,7 +85,7 @@ private Runtime createRuntime() { } private TestCaseFinished testCaseFinishedWithStatus(Status resultStatus) { - return new TestCaseFinished(ANY_INSTANT, mock(TestCase.class), new Result(resultStatus, ZERO, null)); + return new TestCaseFinished(ANY_INSTANT, new StubTestCase(), new Result(resultStatus, ZERO, null)); } @Test @@ -160,9 +156,7 @@ void should_make_scenario_name_available_to_hooks() { " Given first step\n" + " When second step\n" + " Then third step\n"); - final HookDefinition beforeHook = mock(HookDefinition.class); - when(beforeHook.getLocation()).thenReturn(""); - when(beforeHook.getTagExpression()).thenReturn(""); + final MockHookDefinition beforeHook = new MockHookDefinition(); FeatureSupplier featureSupplier = new StubFeatureSupplier(feature); @@ -171,16 +165,15 @@ void should_make_scenario_name_available_to_hooks() { .withBackendSupplier(new StubBackendSupplier( singletonList(beforeHook), asList( - new StubStepDefinition("first step"), - new StubStepDefinition("second step"), - new StubStepDefinition("third step")), + new io.cucumber.core.backend.StubStepDefinition("first step"), + new io.cucumber.core.backend.StubStepDefinition("second step"), + new io.cucumber.core.backend.StubStepDefinition("third step")), emptyList())) .build(); runtime.run(); - ArgumentCaptor capturedScenario = ArgumentCaptor.forClass(TestCaseState.class); - verify(beforeHook).execute(capturedScenario.capture()); - assertThat(capturedScenario.getValue().getName(), is(equalTo("scenario name"))); + assertEquals(1, beforeHook.executedStates.size()); + assertEquals("scenario name", beforeHook.executedStates.get(0).getName()); } @Test @@ -200,9 +193,9 @@ void should_call_formatter_for_two_scenarios_with_background() { .withFeatureSupplier(new StubFeatureSupplier(feature)) .withAdditionalPlugins(formatterSpy) .withBackendSupplier(new StubBackendSupplier( - new StubStepDefinition("first step"), - new StubStepDefinition("second step"), - new StubStepDefinition("third step"))) + new io.cucumber.core.backend.StubStepDefinition("first step"), + new io.cucumber.core.backend.StubStepDefinition("second step"), + new io.cucumber.core.backend.StubStepDefinition("third step"))) .build() .run(); @@ -249,9 +242,9 @@ void should_call_formatter_for_scenario_outline_with_two_examples_table_and_back .withAdditionalPlugins(formatterSpy) .withEventBus(new TimeServiceEventBus(fixed(EPOCH, of("UTC")), UUID::randomUUID)) .withBackendSupplier(new StubBackendSupplier( - new StubStepDefinition("first step"), - new StubStepDefinition("second step"), - new StubStepDefinition("third step"))) + new io.cucumber.core.backend.StubStepDefinition("first step"), + new io.cucumber.core.backend.StubStepDefinition("second step"), + new io.cucumber.core.backend.StubStepDefinition("third step"))) .build() .run(); @@ -309,7 +302,7 @@ void should_call_formatter_with_correct_sequence_of_events_when_running_in_paral .withFeatureSupplier(new StubFeatureSupplier(feature1, feature2, feature3)) .withAdditionalPlugins(formatterSpy) .withBackendSupplier(new StubBackendSupplier( - new StubStepDefinition("first step"))) + new io.cucumber.core.backend.StubStepDefinition("first step"))) .withRuntimeOptions(new RuntimeOptionsBuilder().setThreads(3).build()) .build() .run(); @@ -487,8 +480,8 @@ void generates_events_for_glue_and_scenario_scoped_glue() { stepDefinedEvents.add(event.getStepDefinition()); }); - final MockedStepDefinition mockedStepDefinition = new MockedStepDefinition(); - final MockedScenarioScopedStepDefinition mockedScenarioScopedStepDefinition = new MockedScenarioScopedStepDefinition(); + final StubStepDefinition mockedStepDefinition = new StubStepDefinition(); + final StubScenarioScopedStepDefinition mockedScenarioScopedStepDefinition = new StubScenarioScopedStepDefinition(); BackendSupplier backendSupplier = new TestBackendSupplier() { @@ -541,7 +534,7 @@ void emits_a_meta_message() { assertThat(meta.getCpu().getName(), matchesPattern(".+")); } - private static final class MockedStepDefinition implements io.cucumber.core.backend.StepDefinition { + private static final class StubStepDefinition implements io.cucumber.core.backend.StepDefinition { @Override public void execute(Object[] args) { @@ -570,7 +563,7 @@ public String getLocation() { } - private static final class MockedScenarioScopedStepDefinition + private static final class StubScenarioScopedStepDefinition implements ScenarioScoped, io.cucumber.core.backend.StepDefinition { @Override @@ -650,4 +643,32 @@ public String toString() { } + private static class MockHookDefinition implements HookDefinition { + final List executedStates = new ArrayList<>(); + + @Override + public void execute(TestCaseState state) { + this.executedStates.add(state); + } + + @Override + public String getTagExpression() { + return ""; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean isDefinedAt(StackTraceElement stackTraceElement) { + return false; + } + + @Override + public String getLocation() { + return ""; + } + } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runtime/ServiceLoaderTestClassLoader.java b/cucumber-core/src/test/java/io/cucumber/core/runtime/ServiceLoaderTestClassLoader.java index f02b8c8980..399917d178 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runtime/ServiceLoaderTestClassLoader.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runtime/ServiceLoaderTestClassLoader.java @@ -14,14 +14,15 @@ /** * Testing classloader for ServiceLoader. This classloader overrides the - * META-INF/services/interface-class-name file with a custom definition. + * META-INF/services/<interface> file with a custom definition. */ public class ServiceLoaderTestClassLoader extends URLClassLoader { Class metaInfInterface; Class[] implementingClasses; /** - * Constructs a classloader which has no META-INF/services/metaInfInterface. + * Constructs a classloader which has no + * META-INF/services/<metaInfInterface>. * * @param metaInfInterface ServiceLoader interface */ @@ -30,10 +31,11 @@ public ServiceLoaderTestClassLoader(Class metaInfInterface) { } /** - * Constructs a fake META-INF/services/metaInfInterface file which contains - * the provided array of classes. When the implementingClasses array is - * null, the META-INF file will not be constructed. The classes from - * implementingClasses are not required to implement the metaInfInterface. + * Constructs a fake META-INF/services/<metaInfInterface> file which + * contains the provided array of classes. When the implementingClasses + * array is null, the META-INF file will not be constructed. The classes + * from implementingClasses are not required to implement the + * metaInfInterface. * * @param metaInfInterface ServiceLoader interface * @param implementingClasses potential subclasses of the ServiceLoader diff --git a/cucumber-core/src/test/java/io/cucumber/core/runtime/ThreadLocalRunnerSupplierTest.java b/cucumber-core/src/test/java/io/cucumber/core/runtime/ThreadLocalRunnerSupplierTest.java index 2e7209c75d..028bc1c8d7 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runtime/ThreadLocalRunnerSupplierTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runtime/ThreadLocalRunnerSupplierTest.java @@ -2,8 +2,8 @@ import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.options.RuntimeOptions; +import io.cucumber.core.plugin.StubTestCase; import io.cucumber.core.runner.Runner; -import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestCaseStarted; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,7 +20,6 @@ import static org.hamcrest.core.IsNull.notNullValue; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.mock; class ThreadLocalRunnerSupplierTest { @@ -83,7 +82,7 @@ void should_limit_runner_bus_scope_to_events_generated_by_runner() { runnerSupplier.get().getBus().registerHandlerFor( TestCaseStarted.class, event -> fail("Should not receive event")); - eventBus.send(new TestCaseStarted(EPOCH, mock(TestCase.class))); + eventBus.send(new TestCaseStarted(EPOCH, new StubTestCase())); } } diff --git a/cucumber-core/src/test/java/io/cucumber/core/runtime/UuidGeneratorServiceLoaderTest.java b/cucumber-core/src/test/java/io/cucumber/core/runtime/UuidGeneratorServiceLoaderTest.java index 3c43a1609e..98e73628f8 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runtime/UuidGeneratorServiceLoaderTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runtime/UuidGeneratorServiceLoaderTest.java @@ -70,6 +70,32 @@ void test_case_2() { assertThat(loader.loadUuidGenerator(), instanceOf(RandomUuidGenerator.class)); } + @Test + void test_case_2_no_exception_when_calling_loadUuidGenerator_many_times() { + Options options = () -> null; + UuidGeneratorServiceLoader loader = new UuidGeneratorServiceLoader( + UuidGeneratorServiceLoaderTest.class::getClassLoader, + options); + UuidGenerator actual = null; + for (int i = 0; i < 1000; i++) { + actual = loader.loadUuidGenerator(); + } + assertThat(actual, instanceOf(RandomUuidGenerator.class)); + } + + @Test + void test_case_2_no_exception_when_instantiating_UuidGeneratorServiceLoader_many_times() { + Options options = () -> null; + UuidGenerator actual = null; + for (int i = 0; i < 1000; i++) { + UuidGeneratorServiceLoader loader = new UuidGeneratorServiceLoader( + UuidGeneratorServiceLoaderTest.class::getClassLoader, + options); + actual = loader.loadUuidGenerator(); + } + assertThat(actual, instanceOf(RandomUuidGenerator.class)); + } + /** * | 3 | RandomUuidGenerator | RandomUuidGenerator, * IncrementingUuidGenerator | RandomUuidGenerator used | diff --git a/cucumber-guice/pom.xml b/cucumber-guice/pom.xml index 3d47ac3c4d..ca7a885565 100644 --- a/cucumber-guice/pom.xml +++ b/cucumber-guice/pom.xml @@ -17,7 +17,6 @@ 3.0 5.11.2 io.cucumber.guice - 5.14.2 @@ -76,12 +75,6 @@ junit-jupiter test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - org.hamcrest hamcrest diff --git a/cucumber-guice/src/test/java/io/cucumber/guice/GuiceBackendTest.java b/cucumber-guice/src/test/java/io/cucumber/guice/GuiceBackendTest.java index 923cd66062..80644e1731 100644 --- a/cucumber-guice/src/test/java/io/cucumber/guice/GuiceBackendTest.java +++ b/cucumber-guice/src/test/java/io/cucumber/guice/GuiceBackendTest.java @@ -1,15 +1,23 @@ package io.cucumber.guice; import io.cucumber.core.backend.BackendProviderService; +import io.cucumber.core.backend.DataTableTypeDefinition; +import io.cucumber.core.backend.DefaultDataTableCellTransformerDefinition; +import io.cucumber.core.backend.DefaultDataTableEntryTransformerDefinition; +import io.cucumber.core.backend.DefaultParameterTransformerDefinition; +import io.cucumber.core.backend.DocStringTypeDefinition; import io.cucumber.core.backend.Glue; +import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.ObjectFactory; +import io.cucumber.core.backend.ParameterTypeDefinition; +import io.cucumber.core.backend.StaticHookDefinition; +import io.cucumber.core.backend.StepDefinition; import io.cucumber.guice.integration.YourInjectorSource; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import java.util.function.Supplier; import static java.lang.Thread.currentThread; @@ -19,38 +27,37 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import static org.junit.jupiter.api.Assertions.assertTrue; -@ExtendWith({ MockitoExtension.class }) class GuiceBackendTest { public final Supplier classLoader = currentThread()::getContextClassLoader; - @Mock - private Glue glue; - - @Mock - private ObjectFactory factory; + private final Glue glue = new StubGlue(); @Test void finds_injector_source_impls_by_classpath_url() { + MockObjectFactory factory = new MockObjectFactory(); GuiceBackend backend = new GuiceBackend(factory, classLoader); backend.loadGlue(glue, singletonList(URI.create("classpath:io/cucumber/guice/integration"))); - verify(factory).addClass(YourInjectorSource.class); + assertTrue(factory.classes.contains(YourInjectorSource.class)); } @Test void finds_injector_source_impls_once_by_classpath_url() { + MockObjectFactory factory = new MockObjectFactory(); GuiceBackend backend = new GuiceBackend(factory, classLoader); backend.loadGlue(glue, asList(URI.create("classpath:io/cucumber/guice/integration"), URI.create("classpath:io/cucumber/guice/integration"))); - verify(factory, times(1)).addClass(YourInjectorSource.class); + assertTrue(factory.classes.contains(YourInjectorSource.class)); + assertEquals(1, factory.classes.size()); } @Test void world_and_snippet_methods_do_nothing() { + MockObjectFactory factory = new MockObjectFactory(); GuiceBackend backend = new GuiceBackend(factory, classLoader); backend.loadGlue(glue, singletonList(URI.create("classpath:io/cucumber/guice/integration"))); backend.buildWorld(); @@ -60,21 +67,121 @@ void world_and_snippet_methods_do_nothing() { @Test void doesnt_save_anything_in_glue() { + MockObjectFactory factory = new MockObjectFactory(); GuiceBackend backend = new GuiceBackend(factory, classLoader); backend.loadGlue(null, singletonList(URI.create("classpath:io/cucumber/guice/integration"))); - verify(factory).addClass(YourInjectorSource.class); + assertTrue(factory.classes.contains(YourInjectorSource.class)); } @Test() void list_of_uris_cant_be_null() { + MockObjectFactory factory = new MockObjectFactory(); GuiceBackend backend = new GuiceBackend(factory, classLoader); assertThrows(NullPointerException.class, () -> backend.loadGlue(glue, null)); } @Test void backend_service_creates_backend() { + MockObjectFactory factory = new MockObjectFactory(); BackendProviderService backendProviderService = new GuiceBackendProviderService(); assertThat(backendProviderService.create(factory, factory, classLoader), is(notNullValue())); } + private static class MockObjectFactory implements ObjectFactory { + List> classes = new ArrayList<>(); + boolean started = false; + boolean stopped = false; + + @Override + public boolean addClass(Class glueClass) { + return classes.add(glueClass); + } + + @Override + public T getInstance(Class glueClass) { + return null; + } + + @Override + public void start() { + started = true; + } + + @Override + public void stop() { + stopped = true; + } + } + + private static class StubGlue implements Glue { + + @Override + public void addBeforeAllHook(StaticHookDefinition beforeAllHook) { + + } + + @Override + public void addAfterAllHook(StaticHookDefinition afterAllHook) { + + } + + @Override + public void addStepDefinition(StepDefinition stepDefinition) { + + } + + @Override + public void addBeforeHook(HookDefinition beforeHook) { + + } + + @Override + public void addAfterHook(HookDefinition afterHook) { + + } + + @Override + public void addBeforeStepHook(HookDefinition beforeStepHook) { + + } + + @Override + public void addAfterStepHook(HookDefinition afterStepHook) { + + } + + @Override + public void addParameterType(ParameterTypeDefinition parameterType) { + + } + + @Override + public void addDataTableType(DataTableTypeDefinition dataTableType) { + + } + + @Override + public void addDefaultParameterTransformer(DefaultParameterTransformerDefinition defaultParameterTransformer) { + + } + + @Override + public void addDefaultDataTableEntryTransformer( + DefaultDataTableEntryTransformerDefinition defaultDataTableEntryTransformer + ) { + + } + + @Override + public void addDefaultDataTableCellTransformer( + DefaultDataTableCellTransformerDefinition defaultDataTableCellTransformer + ) { + + } + + @Override + public void addDocStringType(DocStringTypeDefinition docStringType) { + + } + } } diff --git a/cucumber-java/pom.xml b/cucumber-java/pom.xml index 5f2f15e683..4f06bcb76a 100644 --- a/cucumber-java/pom.xml +++ b/cucumber-java/pom.xml @@ -17,7 +17,6 @@ 3.0 2.18.0 5.11.2 - 5.14.2 @@ -72,12 +71,6 @@ junit-platform-suite test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - com.fasterxml.jackson.core jackson-databind diff --git a/cucumber-java/src/test/java/io/cucumber/java/JavaBackendTest.java b/cucumber-java/src/test/java/io/cucumber/java/JavaBackendTest.java index 5ad1a92826..f7e2522148 100644 --- a/cucumber-java/src/test/java/io/cucumber/java/JavaBackendTest.java +++ b/cucumber-java/src/test/java/io/cucumber/java/JavaBackendTest.java @@ -1,19 +1,23 @@ package io.cucumber.java; +import io.cucumber.core.backend.DataTableTypeDefinition; +import io.cucumber.core.backend.DefaultDataTableCellTransformerDefinition; +import io.cucumber.core.backend.DefaultDataTableEntryTransformerDefinition; +import io.cucumber.core.backend.DefaultParameterTransformerDefinition; +import io.cucumber.core.backend.DocStringTypeDefinition; import io.cucumber.core.backend.Glue; +import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.ObjectFactory; +import io.cucumber.core.backend.ParameterTypeDefinition; +import io.cucumber.core.backend.StaticHookDefinition; import io.cucumber.core.backend.StepDefinition; import io.cucumber.java.steps.Steps; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.function.Executable; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import java.net.URI; +import java.util.ArrayList; import java.util.List; import static java.lang.Thread.currentThread; @@ -23,46 +27,45 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -@ExtendWith(MockitoExtension.class) class JavaBackendTest { - - @Captor - ArgumentCaptor stepDefinition; - - @Mock - private Glue glue; - - @Mock - private ObjectFactory factory; + private MockObjectFactory factory; private JavaBackend backend; @BeforeEach void createBackend() { + factory = new MockObjectFactory(); this.backend = new JavaBackend(factory, factory, currentThread()::getContextClassLoader); } @Test void finds_step_definitions_by_classpath_url() { + MockGlue glue = new MockGlue(); + backend.loadGlue(glue, singletonList(URI.create("classpath:io/cucumber/java/steps"))); backend.buildWorld(); - verify(factory).addClass(Steps.class); + + assertIterableEquals(List.of(Steps.class), factory.classes); } @Test void finds_step_definitions_once_by_classpath_url() { + MockGlue glue = new MockGlue(); + backend.loadGlue(glue, asList(URI.create("classpath:io/cucumber/java/steps"), URI.create("classpath:io/cucumber/java/steps"))); backend.buildWorld(); - verify(factory, times(1)).addClass(Steps.class); + + assertIterableEquals(List.of(Steps.class), factory.classes); } @Test void detects_subclassed_glue_and_throws_exception() { + MockGlue glue = new MockGlue(); Executable testMethod = () -> backend.loadGlue(glue, asList(URI.create("classpath:io/cucumber/java/steps"), URI.create("classpath:io/cucumber/java/incorrectlysubclassedsteps"))); InvalidMethodException expectedThrown = assertThrows(InvalidMethodException.class, testMethod); @@ -72,10 +75,12 @@ void detects_subclassed_glue_and_throws_exception() { @Test void detects_repeated_annotations() { + MockGlue glue = new MockGlue(); + backend.loadGlue(glue, singletonList(URI.create("classpath:io/cucumber/java/repeatable"))); - verify(glue, times(2)).addStepDefinition(stepDefinition.capture()); - List patterns = stepDefinition.getAllValues() + assertEquals(2, glue.stepDefinitions.size()); + List patterns = glue.stepDefinitions .stream() .map(StepDefinition::getPattern) .collect(toList()); @@ -83,4 +88,88 @@ void detects_repeated_annotations() { } + private static class MockGlue implements Glue { + final List stepDefinitions = new ArrayList<>(); + + @Override + public void addBeforeAllHook(StaticHookDefinition beforeAllHook) { + } + + @Override + public void addAfterAllHook(StaticHookDefinition afterAllHook) { + } + + @Override + public void addStepDefinition(StepDefinition stepDefinition) { + stepDefinitions.add(stepDefinition); + } + + @Override + public void addBeforeHook(HookDefinition beforeHook) { + } + + @Override + public void addAfterHook(HookDefinition afterHook) { + } + + @Override + public void addBeforeStepHook(HookDefinition beforeStepHook) { + } + + @Override + public void addAfterStepHook(HookDefinition afterStepHook) { + } + + @Override + public void addParameterType(ParameterTypeDefinition parameterType) { + } + + @Override + public void addDataTableType(DataTableTypeDefinition dataTableType) { + } + + @Override + public void addDefaultParameterTransformer(DefaultParameterTransformerDefinition defaultParameterTransformer) { + } + + @Override + public void addDefaultDataTableEntryTransformer( + DefaultDataTableEntryTransformerDefinition defaultDataTableEntryTransformer + ) { + } + + @Override + public void addDefaultDataTableCellTransformer( + DefaultDataTableCellTransformerDefinition defaultDataTableCellTransformer + ) { + } + + @Override + public void addDocStringType(DocStringTypeDefinition docStringType) { + } + } + + private class MockObjectFactory implements ObjectFactory { + final List> classes = new ArrayList<>(); + + @Override + public boolean addClass(Class glueClass) { + return classes.add(glueClass); + } + + @Override + public T getInstance(Class glueClass) { + return null; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + } } diff --git a/cucumber-java/src/test/java/io/cucumber/java/JavaHookDefinitionTest.java b/cucumber-java/src/test/java/io/cucumber/java/JavaHookDefinitionTest.java index e1616cd003..51284c74ea 100644 --- a/cucumber-java/src/test/java/io/cucumber/java/JavaHookDefinitionTest.java +++ b/cucumber-java/src/test/java/io/cucumber/java/JavaHookDefinitionTest.java @@ -1,15 +1,13 @@ package io.cucumber.java; import io.cucumber.core.backend.Lookup; +import io.cucumber.core.backend.Status; import io.cucumber.core.backend.TestCaseState; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; import java.lang.reflect.Method; +import java.net.URI; +import java.util.Collection; import java.util.List; import static org.hamcrest.CoreMatchers.startsWith; @@ -18,8 +16,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @SuppressWarnings({ "WeakerAccess" }) -@ExtendWith({ MockitoExtension.class }) -@MockitoSettings(strictness = Strictness.STRICT_STUBS) public class JavaHookDefinitionTest { private final Lookup lookup = new Lookup() { @@ -31,8 +27,7 @@ public T getInstance(Class glueClass) { } }; - @Mock - private TestCaseState state; + private TestCaseState state = new StubTestCaseState(); private boolean invoked = false; @@ -122,4 +117,55 @@ public String string_return_type() { return ""; } + private class StubTestCaseState implements TestCaseState { + @Override + public Collection getSourceTagNames() { + return null; + } + + @Override + public Status getStatus() { + return null; + } + + @Override + public boolean isFailed() { + return false; + } + + @Override + public void attach(byte[] data, String mediaType, String name) { + + } + + @Override + public void attach(String data, String mediaType, String name) { + + } + + @Override + public void log(String text) { + + } + + @Override + public String getName() { + return null; + } + + @Override + public String getId() { + return null; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public Integer getLine() { + return null; + } + } } diff --git a/cucumber-java8/pom.xml b/cucumber-java8/pom.xml index 24a55dc44f..10c81522b2 100644 --- a/cucumber-java8/pom.xml +++ b/cucumber-java8/pom.xml @@ -16,7 +16,6 @@ 1.1.2 3.0 5.11.2 - 5.14.2 0.6.3 @@ -71,13 +70,6 @@ test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - - org.hamcrest hamcrest diff --git a/cucumber-java8/src/test/java/io/cucumber/java8/Java8BackendTest.java b/cucumber-java8/src/test/java/io/cucumber/java8/Java8BackendTest.java index 6580190c02..49e5c3e451 100644 --- a/cucumber-java8/src/test/java/io/cucumber/java8/Java8BackendTest.java +++ b/cucumber-java8/src/test/java/io/cucumber/java8/Java8BackendTest.java @@ -1,51 +1,133 @@ package io.cucumber.java8; +import io.cucumber.core.backend.DataTableTypeDefinition; +import io.cucumber.core.backend.DefaultDataTableCellTransformerDefinition; +import io.cucumber.core.backend.DefaultDataTableEntryTransformerDefinition; +import io.cucumber.core.backend.DefaultParameterTransformerDefinition; +import io.cucumber.core.backend.DocStringTypeDefinition; import io.cucumber.core.backend.Glue; +import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.ObjectFactory; +import io.cucumber.core.backend.ParameterTypeDefinition; +import io.cucumber.core.backend.StaticHookDefinition; +import io.cucumber.core.backend.StepDefinition; import io.cucumber.java8.steps.Steps; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import static java.lang.Thread.currentThread; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; -@ExtendWith(MockitoExtension.class) class Java8BackendTest { - - @Mock - private Glue glue; - - @Mock - private ObjectFactory factory; + private MockObjectFactory factory; private Java8Backend backend; @BeforeEach void createBackend() { + factory = new MockObjectFactory(); this.backend = new Java8Backend(factory, factory, currentThread()::getContextClassLoader); } @Test void finds_step_definitions_by_classpath_url() { - backend.loadGlue(glue, singletonList(URI.create("classpath:io/cucumber/java8/steps"))); + backend.loadGlue(new StubGlue(), singletonList(URI.create("classpath:io/cucumber/java8/steps"))); backend.buildWorld(); - verify(factory).addClass(Steps.class); + assertIterableEquals(List.of(Steps.class), factory.classes); } @Test void finds_step_definitions_once_by_classpath_url() { - backend.loadGlue(glue, + backend.loadGlue(new StubGlue(), asList(URI.create("classpath:io/cucumber/java8/steps"), URI.create("classpath:io/cucumber/java8/steps"))); backend.buildWorld(); - verify(factory, times(1)).addClass(Steps.class); + assertIterableEquals(List.of(Steps.class), factory.classes); + } + + private static class StubGlue implements Glue { + @Override + public void addBeforeAllHook(StaticHookDefinition beforeAllHook) { + } + + @Override + public void addAfterAllHook(StaticHookDefinition afterAllHook) { + } + + @Override + public void addStepDefinition(StepDefinition stepDefinition) { + } + + @Override + public void addBeforeHook(HookDefinition beforeHook) { + } + + @Override + public void addAfterHook(HookDefinition afterHook) { + } + + @Override + public void addBeforeStepHook(HookDefinition beforeStepHook) { + } + + @Override + public void addAfterStepHook(HookDefinition afterStepHook) { + } + + @Override + public void addParameterType(ParameterTypeDefinition parameterType) { + } + + @Override + public void addDataTableType(DataTableTypeDefinition dataTableType) { + } + + @Override + public void addDefaultParameterTransformer(DefaultParameterTransformerDefinition defaultParameterTransformer) { + } + + @Override + public void addDefaultDataTableEntryTransformer( + DefaultDataTableEntryTransformerDefinition defaultDataTableEntryTransformer + ) { + } + + @Override + public void addDefaultDataTableCellTransformer( + DefaultDataTableCellTransformerDefinition defaultDataTableCellTransformer + ) { + } + + @Override + public void addDocStringType(DocStringTypeDefinition docStringType) { + } } + private static class MockObjectFactory implements ObjectFactory { + List> classes = new ArrayList<>(); + @Override + public boolean addClass(Class glueClass) { + return classes.add(glueClass); + } + + @Override + public T getInstance(Class glueClass) { + return null; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + } } diff --git a/cucumber-java8/src/test/java/io/cucumber/java8/LambdaGlueTest.java b/cucumber-java8/src/test/java/io/cucumber/java8/LambdaGlueTest.java index f502ffab10..2fcd65b64c 100644 --- a/cucumber-java8/src/test/java/io/cucumber/java8/LambdaGlueTest.java +++ b/cucumber-java8/src/test/java/io/cucumber/java8/LambdaGlueTest.java @@ -7,12 +7,14 @@ import io.cucumber.core.backend.DocStringTypeDefinition; import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.ParameterTypeDefinition; +import io.cucumber.core.backend.Status; import io.cucumber.core.backend.StepDefinition; import io.cucumber.core.backend.TestCaseState; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; +import java.net.URI; +import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import static io.cucumber.java8.LambdaGlue.DEFAULT_AFTER_ORDER; @@ -25,7 +27,7 @@ class LambdaGlueTest { private final AtomicBoolean invoked = new AtomicBoolean(); - private final TestCaseState state = Mockito.mock(TestCaseState.class); + private final TestCaseState state = new StubTestCaseState(); private final LambdaGlue lambdaGlue = new LambdaGlue() { }; @@ -200,4 +202,55 @@ void testAfterStepHook() { assertHook(afterStepHook, "taxExpression", 42); } + private static class StubTestCaseState implements TestCaseState { + @Override + public Collection getSourceTagNames() { + return null; + } + + @Override + public Status getStatus() { + return null; + } + + @Override + public boolean isFailed() { + return false; + } + + @Override + public void attach(byte[] data, String mediaType, String name) { + + } + + @Override + public void attach(String data, String mediaType, String name) { + + } + + @Override + public void log(String text) { + + } + + @Override + public String getName() { + return null; + } + + @Override + public String getId() { + return null; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public Integer getLine() { + return null; + } + } } diff --git a/cucumber-junit/pom.xml b/cucumber-junit/pom.xml index c7691c8e21..384579612d 100644 --- a/cucumber-junit/pom.xml +++ b/cucumber-junit/pom.xml @@ -16,7 +16,6 @@ 3.0 5.11.2 4.13.2 - 5.14.2 io.cucumber.junit @@ -64,12 +63,6 @@ junit-vintage-engine test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - org.hamcrest hamcrest diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/CucumberTest.java b/cucumber-junit/src/test/java/io/cucumber/junit/CucumberTest.java index 3d5ed1185a..29fc5e2c6e 100644 --- a/cucumber-junit/src/test/java/io/cucumber/junit/CucumberTest.java +++ b/cucumber-junit/src/test/java/io/cucumber/junit/CucumberTest.java @@ -14,23 +14,23 @@ import org.junit.runner.notification.RunNotifier; import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; -import org.mockito.InOrder; -import org.mockito.Mockito; import java.io.File; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import static java.util.Collections.emptyList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.argThat; class CucumberTest { @@ -96,67 +96,57 @@ void finds_no_features_when_explicit_feature_path_has_no_features() throws Initi } @Test - void cucumber_can_run_features_in_parallel() throws Exception { + void cucumber_can_run_features_in_parallel() { RunNotifier notifier = new RunNotifier(); - RunListener listener = Mockito.mock(RunListener.class); + MockRunListener listener = new MockRunListener(); notifier.addListener(listener); ParallelComputer computer = new ParallelComputer(true, true); Request.classes(computer, ValidEmpty.class).getRunner().run(notifier); { - InOrder order = Mockito.inOrder(listener); - - 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) - .testStarted(argThat(new DescriptionMatcher("Followed by some examples #2(Feature A)"))); - order.verify(listener) - .testFinished(argThat(new DescriptionMatcher("Followed by some examples #2(Feature A)"))); - order.verify(listener) - .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)"))); + List events = listener.events.stream() + .filter(runListenerEvent -> runListenerEvent.description.startsWith("Followed by some examples")) + .collect(Collectors.toList()); + assertIterableEquals(List.of( + new RunListenerEvent("testStarted", "Followed by some examples #1(Feature A)"), + new RunListenerEvent("testFinished", "Followed by some examples #1(Feature A)"), + new RunListenerEvent("testStarted", "Followed by some examples #2(Feature A)"), + new RunListenerEvent("testFinished", "Followed by some examples #2(Feature A)"), + new RunListenerEvent("testStarted", "Followed by some examples #3(Feature A)"), + new RunListenerEvent("testFinished", "Followed by some examples #3(Feature A)")), events); } { - InOrder order = Mockito.inOrder(listener); - order.verify(listener).testStarted(argThat(new DescriptionMatcher("A(Feature B)"))); - 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 #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)"))); + List events = listener.events.stream() + .filter(runListenerEvent -> runListenerEvent.description.endsWith("(Feature B)")) + .collect(Collectors.toList()); + assertIterableEquals(List.of( + new RunListenerEvent("testStarted", "A(Feature B)"), + new RunListenerEvent("testFinished", "A(Feature B)"), + new RunListenerEvent("testStarted", "B(Feature B)"), + new RunListenerEvent("testFinished", "B(Feature B)"), + new RunListenerEvent("testStarted", "C #1(Feature B)"), + new RunListenerEvent("testFinished", "C #1(Feature B)"), + new RunListenerEvent("testStarted", "C #2(Feature B)"), + new RunListenerEvent("testFinished", "C #2(Feature B)"), + new RunListenerEvent("testStarted", "C #3(Feature B)"), + new RunListenerEvent("testFinished", "C #3(Feature B)")), events); } } @Test - void cucumber_distinguishes_between_identical_features() throws Exception { + void cucumber_distinguishes_between_identical_features() { RunNotifier notifier = new RunNotifier(); - RunListener listener = Mockito.mock(RunListener.class); + MockRunListener listener = new MockRunListener(); 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)"))); - } + List events = listener.events.stream() + .filter(runListenerEvent -> runListenerEvent.description.startsWith("A single scenario")) + .collect(Collectors.toList()); + assertIterableEquals(List.of( + new RunListenerEvent("testStarted", "A single scenario(A feature with a single scenario #1)"), + new RunListenerEvent("testFinished", "A single scenario(A feature with a single scenario #1)"), + new RunListenerEvent("testStarted", "A single scenario(A feature with a single scenario #2)"), + new RunListenerEvent("testFinished", "A single scenario(A feature with a single scenario #2)")), events); } @Test @@ -243,4 +233,39 @@ public static class FormatterWithLexerErrorFeature { } + private static class MockRunListener extends RunListener { + List events = new ArrayList<>(); + @Override + public void testStarted(Description description) { + this.events.add(new RunListenerEvent("testStarted", description.getDisplayName())); + } + + @Override + public void testFinished(Description description) { + this.events.add(new RunListenerEvent("testFinished", description.getDisplayName())); + } + + } + + public static class RunListenerEvent { + String eventName; + String description; + public RunListenerEvent(String eventName, String description) { + this.eventName = eventName; + this.description = description; + } + + public boolean equals(Object o) { + if (o instanceof RunListenerEvent) { + return this.toString().equals(o.toString()); + } else { + return false; + } + } + + public String toString() { + return eventName + ", description=" + description; + } + + } } diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/DescriptionMatcher.java b/cucumber-junit/src/test/java/io/cucumber/junit/DescriptionMatcher.java deleted file mode 100644 index 58ef3879da..0000000000 --- a/cucumber-junit/src/test/java/io/cucumber/junit/DescriptionMatcher.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.cucumber.junit; - -import org.junit.runner.Description; -import org.mockito.ArgumentMatcher; - -final class DescriptionMatcher implements ArgumentMatcher { - - private final String name; - - DescriptionMatcher(String name) { - this.name = name; - } - - @Override - public boolean matches(Description argument) { - return argument != null && argument.getDisplayName().equals(name); - } - - @Override - public String toString() { - return name; - } - -} diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/FailureMatcher.java b/cucumber-junit/src/test/java/io/cucumber/junit/FailureMatcher.java deleted file mode 100644 index 79ac340ae7..0000000000 --- a/cucumber-junit/src/test/java/io/cucumber/junit/FailureMatcher.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.cucumber.junit; - -import org.junit.runner.notification.Failure; -import org.mockito.ArgumentMatcher; - -final class FailureMatcher implements ArgumentMatcher { - - private final String name; - - FailureMatcher(String name) { - this.name = name; - } - - @Override - public boolean matches(Failure argument) { - return argument != null && argument.getDescription().getDisplayName().equals(name); - } - -} diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java b/cucumber-junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java index ff6b0bb531..9ed6a018a7 100644 --- a/cucumber-junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java +++ b/cucumber-junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java @@ -19,13 +19,14 @@ import org.junit.runner.Description; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; -import org.mockito.ArgumentCaptor; -import org.mockito.InOrder; +import org.junit.runner.notification.StoppedByUserException; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -33,11 +34,9 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; class FeatureRunnerTest { @@ -141,24 +140,25 @@ void should_not_issue_notification_for_steps_by_default_scenario_outline_with_tw " Examples: examples 2 name\n" + " | id |\n" + " | #3 |\n"); - RunNotifier notifier = runFeatureWithNotifier(feature, new JUnitOptions()); - - InOrder order = inOrder(notifier); - - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario #1(feature name)"))); - order.verify(notifier, times(1)).fireTestFailure(argThat(new FailureMatcher("scenario #1(feature name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario #1(feature name)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario #2(feature name)"))); - order.verify(notifier, times(1)).fireTestFailure(argThat(new FailureMatcher("scenario #2(feature name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario #2(feature name)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario #3(feature name)"))); - order.verify(notifier, times(1)).fireTestFailure(argThat(new FailureMatcher("scenario #3(feature name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario #3(feature name)"))); + MockRunNotifier notifier = runFeatureWithNotifier(feature, new JUnitOptions()); + + assertIterableEquals( + List.of( + new RunNotifierEvent("fireTestStarted", "scenario #1(feature name)"), + new RunNotifierEvent("fireTestFailure", "scenario #1(feature name)"), + new RunNotifierEvent("fireTestFinished", "scenario #1(feature name)"), + new RunNotifierEvent("fireTestStarted", "scenario #2(feature name)"), + new RunNotifierEvent("fireTestFailure", "scenario #2(feature name)"), + new RunNotifierEvent("fireTestFinished", "scenario #2(feature name)"), + new RunNotifierEvent("fireTestStarted", "scenario #3(feature name)"), + new RunNotifierEvent("fireTestFailure", "scenario #3(feature name)"), + new RunNotifierEvent("fireTestFinished", "scenario #3(feature name)")), + notifier.events); } - private RunNotifier runFeatureWithNotifier(Feature feature, JUnitOptions options) { + private MockRunNotifier runFeatureWithNotifier(Feature feature, JUnitOptions options) { FeatureRunner runner = createFeatureRunner(feature, options); - RunNotifier notifier = mock(RunNotifier.class); + MockRunNotifier notifier = new MockRunNotifier(); runner.run(notifier); return notifier; } @@ -175,16 +175,17 @@ void should_not_issue_notification_for_steps_by_default_two_scenarios_with_backg " Scenario: scenario_2 name\n" + " Then step #2\n"); - RunNotifier notifier = runFeatureWithNotifier(feature, new JUnitOptions()); - - InOrder order = inOrder(notifier); - - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario_1 name(feature name)"))); - order.verify(notifier, times(1)).fireTestFailure(argThat(new FailureMatcher("scenario_1 name(feature name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario_1 name(feature name)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario_2 name(feature name)"))); - order.verify(notifier, times(1)).fireTestFailure(argThat(new FailureMatcher("scenario_2 name(feature name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario_2 name(feature name)"))); + MockRunNotifier notifier = runFeatureWithNotifier(feature, new JUnitOptions()); + + assertIterableEquals( + List.of( + new RunNotifierEvent("fireTestStarted", "scenario_1 name(feature name)"), + new RunNotifierEvent("fireTestFailure", "scenario_1 name(feature name)"), + new RunNotifierEvent("fireTestFinished", "scenario_1 name(feature name)"), + new RunNotifierEvent("fireTestStarted", "scenario_2 name(feature name)"), + new RunNotifierEvent("fireTestFailure", "scenario_2 name(feature name)"), + new RunNotifierEvent("fireTestFinished", "scenario_2 name(feature name)")), + notifier.events); } @Test @@ -271,45 +272,49 @@ void step_notification_can_be_turned_on_scenario_outline_with_two_examples_table " | #3 |\n"); JUnitOptions junitOption = new JUnitOptionsBuilder().setStepNotifications(true).build(); - RunNotifier notifier = runFeatureWithNotifier(feature, junitOption); - - InOrder order = inOrder(notifier); - - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario #1"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #1(scenario #1)"))); - order.verify(notifier).fireTestFailure(argThat(new FailureMatcher("step #1(scenario #1)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #1(scenario #1)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #2(scenario #1)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #2(scenario #1)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #2(scenario #1)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #3(scenario #1)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #3(scenario #1)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #3(scenario #1)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario #1"))); - - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario #2"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #1(scenario #2)"))); - order.verify(notifier).fireTestFailure(argThat(new FailureMatcher("step #1(scenario #2)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #1(scenario #2)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #2(scenario #2)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #2(scenario #2)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #2(scenario #2)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #3(scenario #2)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #3(scenario #2)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #3(scenario #2)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario #2"))); - - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario #3"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #1(scenario #3)"))); - order.verify(notifier).fireTestFailure(argThat(new FailureMatcher("step #1(scenario #3)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #1(scenario #3)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #2(scenario #3)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #2(scenario #3)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #2(scenario #3)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #3(scenario #3)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #3(scenario #3)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #3(scenario #3)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario #3"))); + MockRunNotifier notifier = runFeatureWithNotifier(feature, junitOption); + + assertIterableEquals( + List.of( + new RunNotifierEvent("fireTestStarted", "scenario #1"), + new RunNotifierEvent("fireTestStarted", "step #1(scenario #1)"), + new RunNotifierEvent("fireTestFailure", "step #1(scenario #1)"), + new RunNotifierEvent("fireTestFinished", "step #1(scenario #1)"), + new RunNotifierEvent("fireTestStarted", "step #2(scenario #1)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #2(scenario #1)"), + new RunNotifierEvent("fireTestFinished", "step #2(scenario #1)"), + new RunNotifierEvent("fireTestStarted", "step #3(scenario #1)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #3(scenario #1)"), + new RunNotifierEvent("fireTestFinished", "step #3(scenario #1)"), + new RunNotifierEvent("fireTestFailure", "scenario #1"), + new RunNotifierEvent("fireTestFinished", "scenario #1"), + + new RunNotifierEvent("fireTestStarted", "scenario #2"), + new RunNotifierEvent("fireTestStarted", "step #1(scenario #2)"), + new RunNotifierEvent("fireTestFailure", "step #1(scenario #2)"), + new RunNotifierEvent("fireTestFinished", "step #1(scenario #2)"), + new RunNotifierEvent("fireTestStarted", "step #2(scenario #2)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #2(scenario #2)"), + new RunNotifierEvent("fireTestFinished", "step #2(scenario #2)"), + new RunNotifierEvent("fireTestStarted", "step #3(scenario #2)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #3(scenario #2)"), + new RunNotifierEvent("fireTestFinished", "step #3(scenario #2)"), + new RunNotifierEvent("fireTestFailure", "scenario #2"), + new RunNotifierEvent("fireTestFinished", "scenario #2"), + + new RunNotifierEvent("fireTestStarted", "scenario #3"), + new RunNotifierEvent("fireTestStarted", "step #1(scenario #3)"), + new RunNotifierEvent("fireTestFailure", "step #1(scenario #3)"), + new RunNotifierEvent("fireTestFinished", "step #1(scenario #3)"), + new RunNotifierEvent("fireTestStarted", "step #2(scenario #3)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #2(scenario #3)"), + new RunNotifierEvent("fireTestFinished", "step #2(scenario #3)"), + new RunNotifierEvent("fireTestStarted", "step #3(scenario #3)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #3(scenario #3)"), + new RunNotifierEvent("fireTestFinished", "step #3(scenario #3)"), + new RunNotifierEvent("fireTestFailure", "scenario #3"), + new RunNotifierEvent("fireTestFinished", "scenario #3")), + notifier.events); } @Test @@ -325,31 +330,33 @@ void step_notification_can_be_turned_on_two_scenarios_with_background() { " Then another step #2\n"); JUnitOptions junitOption = new JUnitOptionsBuilder().setStepNotifications(true).build(); - RunNotifier notifier = runFeatureWithNotifier(feature, junitOption); - - InOrder order = inOrder(notifier); - - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario_1 name"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #1(scenario_1 name)"))); - order.verify(notifier).fireTestFailure(argThat(new FailureMatcher("step #1(scenario_1 name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #1(scenario_1 name)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #2(scenario_1 name)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #2(scenario_1 name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #2(scenario_1 name)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #3(scenario_1 name)"))); - order.verify(notifier).fireTestAssumptionFailed(argThat(new FailureMatcher("step #3(scenario_1 name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #3(scenario_1 name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario_1 name"))); - - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("scenario_2 name"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("step #1(scenario_2 name)"))); - order.verify(notifier).fireTestFailure(argThat(new FailureMatcher("step #1(scenario_2 name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("step #1(scenario_2 name)"))); - order.verify(notifier).fireTestStarted(argThat(new DescriptionMatcher("another step #2(scenario_2 name)"))); - order.verify(notifier) - .fireTestAssumptionFailed(argThat(new FailureMatcher("another step #2(scenario_2 name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("another step #2(scenario_2 name)"))); - order.verify(notifier).fireTestFinished(argThat(new DescriptionMatcher("scenario_2 name"))); + MockRunNotifier notifier = runFeatureWithNotifier(feature, junitOption); + + assertIterableEquals( + List.of( + new RunNotifierEvent("fireTestStarted", "scenario_1 name"), + new RunNotifierEvent("fireTestStarted", "step #1(scenario_1 name)"), + new RunNotifierEvent("fireTestFailure", "step #1(scenario_1 name)"), + new RunNotifierEvent("fireTestFinished", "step #1(scenario_1 name)"), + new RunNotifierEvent("fireTestStarted", "step #2(scenario_1 name)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #2(scenario_1 name)"), + new RunNotifierEvent("fireTestFinished", "step #2(scenario_1 name)"), + new RunNotifierEvent("fireTestStarted", "step #3(scenario_1 name)"), + new RunNotifierEvent("fireTestAssumptionFailed", "step #3(scenario_1 name)"), + new RunNotifierEvent("fireTestFinished", "step #3(scenario_1 name)"), + new RunNotifierEvent("fireTestFailure", "scenario_1 name"), + new RunNotifierEvent("fireTestFinished", "scenario_1 name"), + + new RunNotifierEvent("fireTestStarted", "scenario_2 name"), + new RunNotifierEvent("fireTestStarted", "step #1(scenario_2 name)"), + new RunNotifierEvent("fireTestFailure", "step #1(scenario_2 name)"), + new RunNotifierEvent("fireTestFinished", "step #1(scenario_2 name)"), + new RunNotifierEvent("fireTestStarted", "another step #2(scenario_2 name)"), + new RunNotifierEvent("fireTestAssumptionFailed", "another step #2(scenario_2 name)"), + new RunNotifierEvent("fireTestFinished", "another step #2(scenario_2 name)"), + new RunNotifierEvent("fireTestFailure", "scenario_2 name"), + new RunNotifierEvent("fireTestFinished", "scenario_2 name")), + notifier.events); } @Test @@ -370,20 +377,19 @@ void should_notify_of_failure_to_create_runners_and_request_test_execution_to_st CucumberExecutionContext context = new CucumberExecutionContext(bus, new ExitStatus(options), runnerSupplier); FeatureRunner featureRunner = FeatureRunner.create(feature, null, filters, context, new JUnitOptions()); - RunNotifier notifier = mock(RunNotifier.class); + MockRunNotifier notifier = new MockRunNotifier(); PickleRunners.PickleRunner pickleRunner = featureRunner.getChildren().get(0); featureRunner.runChild(pickleRunner, notifier); Description description = pickleRunner.getDescription(); - ArgumentCaptor failureArgumentCaptor = ArgumentCaptor.forClass(Failure.class); - - InOrder order = inOrder(notifier); - order.verify(notifier).fireTestStarted(description); - order.verify(notifier).fireTestFailure(failureArgumentCaptor.capture()); - assertThat(failureArgumentCaptor.getValue().getException(), is(equalTo(illegalStateException))); - assertThat(failureArgumentCaptor.getValue().getDescription(), is(equalTo(description))); - order.verify(notifier).pleaseStop(); - order.verify(notifier).fireTestFinished(description); + assertIterableEquals( + List.of( + new RunNotifierEvent("fireTestStarted", description.getDisplayName()), + new RunNotifierEvent("fireTestFailure", description.getDisplayName()), + new RunNotifierEvent("pleaseStop", ""), + new RunNotifierEvent("fireTestFinished", description.getDisplayName())), + notifier.events); + assertEquals(illegalStateException, notifier.events.get(1).throwable); } @Test @@ -416,4 +422,64 @@ void should_filter_pickles() { is("scenario_2 name(feature name)")); } + private static class MockRunNotifier extends RunNotifier { + List events = new ArrayList<>(); + + @Override + public void fireTestStarted(Description description) throws StoppedByUserException { + this.events.add(new RunNotifierEvent("fireTestStarted", description.getDisplayName())); + } + + @Override + public void fireTestFailure(Failure failure) { + this.events.add(new RunNotifierEvent("fireTestFailure", failure.getDescription().getDisplayName(), + failure.getException())); + } + + @Override + public void fireTestAssumptionFailed(Failure failure) { + this.events.add(new RunNotifierEvent("fireTestAssumptionFailed", failure.getDescription().getDisplayName(), + failure.getException())); + } + + @Override + public void fireTestFinished(Description description) { + this.events.add(new RunNotifierEvent("fireTestFinished", description.getDisplayName())); + } + + @Override + public void pleaseStop() { + this.events.add(new RunNotifierEvent("pleaseStop", "")); + } + + } + + private static class RunNotifierEvent { + private final String eventName; + private final String description; + private final Throwable throwable; + public RunNotifierEvent(String eventName, String description) { + this.eventName = eventName; + this.description = description; + this.throwable = null; + } + + public RunNotifierEvent(String eventName, String description, Throwable throwable) { + this.eventName = eventName; + this.description = description; + this.throwable = throwable; + } + + public boolean equals(Object o) { + if (o instanceof RunNotifierEvent) { + return this.toString().equals(o.toString()); + } else { + return false; + } + } + + public String toString() { + return eventName + ", description=" + description; + } + } } diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/JUnitReporterWithStepNotificationsTest.java b/cucumber-junit/src/test/java/io/cucumber/junit/JUnitReporterWithStepNotificationsTest.java index f2f3e76925..7816a89df6 100644 --- a/cucumber-junit/src/test/java/io/cucumber/junit/JUnitReporterWithStepNotificationsTest.java +++ b/cucumber-junit/src/test/java/io/cucumber/junit/JUnitReporterWithStepNotificationsTest.java @@ -6,34 +6,34 @@ import io.cucumber.core.gherkin.Step; import io.cucumber.core.runtime.TimeServiceEventBus; import io.cucumber.junit.PickleRunners.PickleRunner; -import io.cucumber.plugin.event.HookTestStep; +import io.cucumber.plugin.event.Argument; import io.cucumber.plugin.event.Location; import io.cucumber.plugin.event.PickleStepTestStep; import io.cucumber.plugin.event.Result; import io.cucumber.plugin.event.SnippetsSuggestedEvent; import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion; import io.cucumber.plugin.event.Status; +import io.cucumber.plugin.event.StepArgument; import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestCaseFinished; import io.cucumber.plugin.event.TestCaseStarted; +import io.cucumber.plugin.event.TestStep; import io.cucumber.plugin.event.TestStepFinished; import io.cucumber.plugin.event.TestStepStarted; import org.junit.AssumptionViolatedException; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.runner.Description; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; +import org.junit.runner.notification.StoppedByUserException; import org.junit.runners.model.MultipleFailureException; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import java.net.URI; import java.time.Clock; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import static java.time.Duration.ZERO; @@ -44,15 +44,9 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.runner.Description.createTestDescription; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + class JUnitReporterWithStepNotificationsTest { private static final Location scenarioLine = new Location(0, 0); @@ -65,47 +59,26 @@ class JUnitReporterWithStepNotificationsTest { " Scenario: Test scenario\n" + " Given step name\n"); private final Step step = feature.getPickles().get(0).getSteps().get(0); - @Mock - private TestCase testCase; - @Mock - private Description pickleRunnerDescription; - - @Mock - private PickleRunner pickleRunner; - @Mock - private RunNotifier runNotifier; - - @Captor - private ArgumentCaptor failureArgumentCaptor; - - @BeforeEach - void mockPickleRunner() { - when(pickleRunner.getDescription()).thenReturn(pickleRunnerDescription); - Description runnerStepDescription = createTestDescription("", step.getText()); - lenient().when(pickleRunner.describeChild(step)).thenReturn(runnerStepDescription); - } + private final PickleRunner pickleRunner = new MockPickleRunner(step); + private final PickleStepTestStep testStep = new StubPickleStepTestStep(featureUri, step); + private final TestCase testCase = new StubTestCase(); @Test void test_step_started_fires_test_started_for_step() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); jUnitReporter.finishExecutionUnit(); } - private static PickleStepTestStep mockTestStep(Step step) { - PickleStepTestStep testStep = mock(PickleStepTestStep.class); - lenient().when(testStep.getUri()).thenReturn(featureUri); - lenient().when(testStep.getStep()).thenReturn(step); - return testStep; - } - @Test void disconnects_from_bus_once_execution_unit_finished() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); jUnitReporter.finishExecutionUnit(); bus.send(new TestCaseStarted(now(), testCase)); - verify(runNotifier, never()).fireTestStarted(pickleRunner.getDescription()); + assertNull(runNotifier.testStartedDescription); } @Test @@ -115,110 +88,114 @@ void ignores_steps_when_step_notification_are_disabled() { .setStepNotifications(false) .build()); + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Result result = new Result(Status.PASSED, ZERO, null); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier, never()).fireTestStarted(pickleRunner.describeChild(step)); - verify(runNotifier, never()).fireTestFinished(pickleRunner.describeChild(step)); + assertNull(runNotifier.testStartedDescription); + assertNull(runNotifier.testFinishedDescription); } @Test void test_case_finished_fires_test_finished_for_pickle() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Result result = new Result(Status.PASSED, ZERO, null); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier).fireTestStarted(pickleRunner.describeChild(step)); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(pickleRunner.describeChild(step), runNotifier.testStartedDescription); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); } @Test void test_step_finished_fires_assumption_failed_and_test_finished_for_skipped_step() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Result result = new Result(Status.SKIPPED, ZERO, null); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); - verify(runNotifier).fireTestAssumptionFailed(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); - Failure stepFailure = failureArgumentCaptor.getValue(); + assertEquals(1, runNotifier.testAssumptionFailedFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); + Failure stepFailure = runNotifier.testAssumptionFailedFailures.get(0); assertThat(stepFailure.getDescription(), is(equalTo(pickleRunner.describeChild(step)))); assertThat(stepFailure.getException(), instanceOf(SkippedThrowable.class)); assertThat(stepFailure.getException().getMessage(), is(equalTo("This step is skipped"))); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier, times(2)).fireTestAssumptionFailed(failureArgumentCaptor.capture()); - Failure pickleFailure = failureArgumentCaptor.getValue(); + assertEquals(2, runNotifier.testAssumptionFailedFailures.size()); + Failure pickleFailure = runNotifier.testAssumptionFailedFailures.get(1); assertThat(pickleFailure.getDescription(), is(equalTo(pickleRunner.getDescription()))); assertThat(pickleFailure.getException(), instanceOf(SkippedThrowable.class)); assertThat(pickleFailure.getException().getMessage(), is(equalTo("This scenario is skipped"))); - } @Test void test_step_finished_fires_assumption_failed_and_test_finished_for_skipped_step_with_assumption_violated() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Throwable exception = new AssumptionViolatedException("Oops"); Result result = new Result(Status.SKIPPED, ZERO, exception); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); - verify(runNotifier).fireTestAssumptionFailed(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(1, runNotifier.testAssumptionFailedFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure stepFailure = failureArgumentCaptor.getValue(); + Failure stepFailure = runNotifier.testAssumptionFailedFailures.get(0); assertThat(stepFailure.getDescription(), is(equalTo(pickleRunner.describeChild(step)))); assertThat(stepFailure.getException(), is(equalTo(exception))); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier, times(2)).fireTestAssumptionFailed(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(2, runNotifier.testAssumptionFailedFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure pickleFailure = failureArgumentCaptor.getValue(); + Failure pickleFailure = runNotifier.testAssumptionFailedFailures.get(1); assertThat(pickleFailure.getDescription(), is(equalTo(pickleRunner.getDescription()))); assertThat(pickleFailure.getException(), is(equalTo(exception))); } @Test void test_step_finished_fires_test_failure_and_test_finished_for_skipped_step_with_pending_exception() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Throwable exception = new TestPendingException("Oops"); Result result = new Result(Status.PENDING, ZERO, exception); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); - verify(runNotifier).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(1, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure stepFailure = failureArgumentCaptor.getValue(); + Failure stepFailure = runNotifier.testFailures.get(0); assertThat(stepFailure.getDescription(), is(equalTo(pickleRunner.describeChild(step)))); assertThat(stepFailure.getException(), is(equalTo(exception))); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier, times(2)).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(2, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure pickleFailure = failureArgumentCaptor.getValue(); + Failure pickleFailure = runNotifier.testFailures.get(1); assertThat(pickleFailure.getDescription(), is(equalTo(pickleRunner.getDescription()))); assertThat(pickleFailure.getException(), is(equalTo(exception))); @@ -226,29 +203,30 @@ void test_step_finished_fires_test_failure_and_test_finished_for_skipped_step_wi @Test void test_step_undefined_fires_test_failure_and_test_finished_for_undefined_step() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); Suggestion suggestion = new Suggestion("step name", singletonList("some snippet")); bus.send(new SnippetsSuggestedEvent(now(), featureUri, scenarioLine, scenarioLine, suggestion)); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Throwable exception = new CucumberException("No step definitions found"); Result result = new Result(Status.UNDEFINED, ZERO, exception); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); - verify(runNotifier).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(1, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure stepFailure = failureArgumentCaptor.getValue(); + Failure stepFailure = runNotifier.testFailures.get(0); assertThat(stepFailure.getDescription(), is(equalTo(pickleRunner.describeChild(step)))); assertThat(stepFailure.getException(), is(equalTo(exception))); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier, times(2)).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(2, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure pickleFailure = failureArgumentCaptor.getValue(); + Failure pickleFailure = runNotifier.testFailures.get(1); assertThat(pickleFailure.getDescription(), is(equalTo(pickleRunner.getDescription()))); assertThat(pickleFailure.getException().getMessage(), is("" + "The step 'step name' is undefined.\n" + @@ -259,77 +237,79 @@ void test_step_undefined_fires_test_failure_and_test_finished_for_undefined_step @Test void test_step_finished_fires_test_failure_and_test_finished_for_failed_step() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Throwable exception = new Exception("Oops"); Result result = new Result(Status.FAILED, ZERO, exception); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); - verify(runNotifier).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(1, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure stepFailure = failureArgumentCaptor.getValue(); + Failure stepFailure = runNotifier.testFailures.get(0); assertThat(stepFailure.getDescription(), is(equalTo(pickleRunner.describeChild(step)))); assertThat(stepFailure.getException(), is(equalTo(exception))); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier, times(2)).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(2, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure pickleFailure = failureArgumentCaptor.getValue(); + Failure pickleFailure = runNotifier.testFailures.get(1); assertThat(pickleFailure.getDescription(), is(equalTo(pickleRunner.getDescription()))); assertThat(pickleFailure.getException(), is(equalTo(exception))); } @Test void test_step_finished_fires_test_failure_and_test_finished_for_failed_hook() { - + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); Result stepResult = new Result(Status.PASSED, ZERO, null); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), stepResult)); + bus.send(new TestStepFinished(now(), testCase, testStep, stepResult)); - bus.send(new TestStepStarted(now(), testCase, mock(HookTestStep.class))); + bus.send(new TestStepStarted(now(), testCase, new StubHookTestStep())); Throwable exception = new Exception("Oops"); Result result = new Result(Status.FAILED, ZERO, exception); - bus.send(new TestStepFinished(now(), testCase, mock(HookTestStep.class), result)); + bus.send(new TestStepFinished(now(), testCase, new StubHookTestStep(), result)); // Hooks are not included in step failure - verify(runNotifier, never()).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(0, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(1, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - Failure pickleFailure = failureArgumentCaptor.getValue(); + Failure pickleFailure = runNotifier.testFailures.get(0); assertThat(pickleFailure.getDescription(), is(equalTo(pickleRunner.getDescription()))); assertThat(pickleFailure.getException(), is(equalTo(exception))); } @Test void test_step_finished_fires_test_failure_and_test_finished_for_failed_step_with_multiple_failure_exception() { + MockRunNotifier runNotifier = new MockRunNotifier(); jUnitReporter.startExecutionUnit(pickleRunner, runNotifier); bus.send(new TestCaseStarted(now(), testCase)); - bus.send(new TestStepStarted(now(), testCase, mockTestStep(step))); + bus.send(new TestStepStarted(now(), testCase, testStep)); List failures = asList( new Exception("Oops"), new Exception("I did it again")); Throwable exception = new MultipleFailureException(failures); Result result = new Result(Status.FAILED, ZERO, exception); - bus.send(new TestStepFinished(now(), testCase, mockTestStep(step), result)); + bus.send(new TestStepFinished(now(), testCase, testStep, result)); - verify(runNotifier, times(2)).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(2, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - List stepFailure = failureArgumentCaptor.getAllValues(); + List stepFailure = runNotifier.testFailures; assertThat(stepFailure.get(0).getDescription(), is(equalTo(pickleRunner.describeChild(step)))); assertThat(stepFailure.get(0).getException(), is(equalTo(failures.get(0)))); @@ -339,18 +319,181 @@ void test_step_finished_fires_test_failure_and_test_finished_for_failed_step_wit bus.send(new TestCaseFinished(now(), testCase, result)); - verify(runNotifier, times(4)).fireTestFailure(failureArgumentCaptor.capture()); - verify(runNotifier).fireTestFinished(pickleRunner.describeChild(step)); + assertEquals(4, runNotifier.testFailures.size()); + assertEquals(pickleRunner.describeChild(step), runNotifier.testFinishedDescription); - List pickleFailure = failureArgumentCaptor.getAllValues(); + List pickleFailure = runNotifier.testFailures; - // Mockito recapture all arguments on .capture() so we end up with the - // original 2, those 2 repeated and the finally the 2 we expect. - assertThat(pickleFailure.get(4).getDescription(), is(equalTo(pickleRunner.getDescription()))); - assertThat(pickleFailure.get(4).getException(), is(equalTo(failures.get(0)))); + assertThat(pickleFailure.get(2).getDescription(), is(equalTo(pickleRunner.getDescription()))); + assertThat(pickleFailure.get(2).getException(), is(equalTo(failures.get(0)))); - assertThat(pickleFailure.get(5).getDescription(), is(equalTo(pickleRunner.getDescription()))); - assertThat(pickleFailure.get(5).getException(), is(equalTo(failures.get(1)))); + assertThat(pickleFailure.get(3).getDescription(), is(equalTo(pickleRunner.getDescription()))); + assertThat(pickleFailure.get(3).getException(), is(equalTo(failures.get(1)))); } + private static class MockPickleRunner implements PickleRunner { + private final Map childDescriptions = new HashMap<>(); + private final Description description; + + public MockPickleRunner(io.cucumber.plugin.event.Step step) { + childDescriptions.put(step, Description.createTestDescription("", step.getText())); + description = Description.createTestDescription("", "pickle name"); + } + + @Override + public void run(RunNotifier notifier) { + } + + @Override + public Description getDescription() { + return description; + } + + @Override + public Description describeChild(io.cucumber.plugin.event.Step step) { + return childDescriptions.get(step); + } + } + + private static class StubPickleStepTestStep implements PickleStepTestStep { + private final URI uri; + private final Step step; + + public StubPickleStepTestStep(URI featureUri, Step step) { + uri = featureUri; + this.step = step; + } + + @Override + public String getPattern() { + return null; + } + + @Override + public io.cucumber.plugin.event.Step getStep() { + return step; + } + + @Override + public List getDefinitionArgument() { + return null; + } + + @Override + public StepArgument getStepArgument() { + return null; + } + + @Override + public int getStepLine() { + return 0; + } + + @Override + public URI getUri() { + return uri; + } + + @Override + public String getStepText() { + return null; + } + + @Override + public String getCodeLocation() { + return null; + } + + @Override + public UUID getId() { + return null; + } + } + + private static class StubTestCase implements TestCase { + @Override + public Integer getLine() { + return null; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getKeyword() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getScenarioDesignation() { + return null; + } + + @Override + public List getTags() { + return null; + } + + @Override + public List getTestSteps() { + return null; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public UUID getId() { + return null; + } + } + + private static class MockRunNotifier extends RunNotifier { + List testAssumptionFailedFailures = new ArrayList<>(); + List testFailures = new ArrayList<>(); + + Description testStartedDescription; + Description testFinishedDescription; + + @Override + public void fireTestAssumptionFailed(Failure failure) { + this.testAssumptionFailedFailures.add(failure); + } + + @Override + public void fireTestFailure(Failure failure) { + this.testFailures.add(failure); + } + + @Override + public void fireTestStarted(Description description) throws StoppedByUserException { + this.testStartedDescription = description; + } + + @Override + public void fireTestFinished(Description description) { + this.testFinishedDescription = description; + } + } + + private static class StubHookTestStep implements TestStep { + @Override + public String getCodeLocation() { + return null; + } + + @Override + public UUID getId() { + return null; + } + } } diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java b/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java index cca3622051..56cf3449d4 100644 --- a/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java +++ b/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithNoStepDescriptionsTest.java @@ -18,13 +18,12 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -import static org.mockito.Mockito.mock; class PickleRunnerWithNoStepDescriptionsTest { final EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); final Options options = RuntimeOptions.defaultOptions(); - final RunnerSupplier runnerSupplier = mock(RunnerSupplier.class); + final RunnerSupplier runnerSupplier = new StubRunnerSupplier(); final CucumberExecutionContext context = new CucumberExecutionContext(bus, new ExitStatus(options), runnerSupplier); @Test diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java b/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java index 83f3cd4ff1..862189ff4a 100644 --- a/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java +++ b/cucumber-junit/src/test/java/io/cucumber/junit/PickleRunnerWithStepDescriptionsTest.java @@ -22,13 +22,12 @@ import static io.cucumber.junit.TestPickleBuilder.picklesFromFeature; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.mockito.Mockito.mock; class PickleRunnerWithStepDescriptionsTest { final EventBus bus = new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID); final Options options = RuntimeOptions.defaultOptions(); - final RunnerSupplier runnerSupplier = mock(RunnerSupplier.class); + final RunnerSupplier runnerSupplier = new StubRunnerSupplier(); final CucumberExecutionContext context = new CucumberExecutionContext(bus, new ExitStatus(options), runnerSupplier); @Test diff --git a/cucumber-junit/src/test/java/io/cucumber/junit/StubRunnerSupplier.java b/cucumber-junit/src/test/java/io/cucumber/junit/StubRunnerSupplier.java new file mode 100644 index 0000000000..70feaec53d --- /dev/null +++ b/cucumber-junit/src/test/java/io/cucumber/junit/StubRunnerSupplier.java @@ -0,0 +1,11 @@ +package io.cucumber.junit; + +import io.cucumber.core.runner.Runner; +import io.cucumber.core.runtime.RunnerSupplier; + +class StubRunnerSupplier implements RunnerSupplier { + @Override + public Runner get() { + return null; + } +} diff --git a/cucumber-spring/pom.xml b/cucumber-spring/pom.xml index fcb2683df5..62a2759804 100644 --- a/cucumber-spring/pom.xml +++ b/cucumber-spring/pom.xml @@ -17,7 +17,6 @@ 5.11.2 6.1.13 io.cucumber.spring - 5.14.2 @@ -90,12 +89,6 @@ ${hamcrest.version} test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - diff --git a/cucumber-spring/src/test/java/io/cucumber/spring/SpringBackendTest.java b/cucumber-spring/src/test/java/io/cucumber/spring/SpringBackendTest.java index f3f8a1b035..636689967e 100644 --- a/cucumber-spring/src/test/java/io/cucumber/spring/SpringBackendTest.java +++ b/cucumber-spring/src/test/java/io/cucumber/spring/SpringBackendTest.java @@ -1,38 +1,45 @@ package io.cucumber.spring; +import io.cucumber.core.backend.DataTableTypeDefinition; +import io.cucumber.core.backend.DefaultDataTableCellTransformerDefinition; +import io.cucumber.core.backend.DefaultDataTableEntryTransformerDefinition; +import io.cucumber.core.backend.DefaultParameterTransformerDefinition; +import io.cucumber.core.backend.DocStringTypeDefinition; import io.cucumber.core.backend.Glue; +import io.cucumber.core.backend.HookDefinition; import io.cucumber.core.backend.ObjectFactory; +import io.cucumber.core.backend.ParameterTypeDefinition; +import io.cucumber.core.backend.StaticHookDefinition; +import io.cucumber.core.backend.StepDefinition; import io.cucumber.spring.annotationconfig.AnnotationContextConfiguration; import io.cucumber.spring.cucumbercontextconfigannotation.AbstractWithComponentAnnotation; import io.cucumber.spring.cucumbercontextconfigannotation.AnnotatedInterface; import io.cucumber.spring.cucumbercontextconfigannotation.WithMetaAnnotation; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import static java.lang.Thread.currentThread; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -@ExtendWith(MockitoExtension.class) class SpringBackendTest { - @Mock - private Glue glue; + private final Glue glue = new MockGlue(); - @Mock - private ObjectFactory factory; + private MockObjectFactory factory; private SpringBackend backend; @BeforeEach void createBackend() { + this.factory = new MockObjectFactory(); this.backend = new SpringBackend(factory, currentThread()::getContextClassLoader); } @@ -40,7 +47,7 @@ void createBackend() { void finds_annotation_context_configuration_by_classpath_url() { backend.loadGlue(glue, singletonList(URI.create("classpath:io/cucumber/spring/annotationconfig"))); backend.buildWorld(); - verify(factory).addClass(AnnotationContextConfiguration.class); + assertTrue(factory.classes.contains(AnnotationContextConfiguration.class)); } @Test @@ -49,7 +56,8 @@ void finds_annotaiton_context_configuration_once_by_classpath_url() { URI.create("classpath:io/cucumber/spring/annotationconfig"), URI.create("classpath:io/cucumber/spring/annotationconfig"))); backend.buildWorld(); - verify(factory, times(1)).addClass(AnnotationContextConfiguration.class); + assertTrue(factory.classes.contains(AnnotationContextConfiguration.class)); + assertEquals(1, factory.classes.size()); } @Test @@ -57,7 +65,7 @@ void ignoresAbstractClassWithCucumberContextConfiguration() { backend.loadGlue(glue, singletonList( URI.create("classpath:io/cucumber/spring/cucumbercontextconfigannotation"))); backend.buildWorld(); - verify(factory, times(0)).addClass(AbstractWithComponentAnnotation.class); + assertFalse(factory.classes.contains(AbstractWithComponentAnnotation.class)); } @Test @@ -65,7 +73,7 @@ void ignoresInterfaceWithCucumberContextConfiguration() { backend.loadGlue(glue, singletonList( URI.create("classpath:io/cucumber/spring/cucumbercontextconfigannotation"))); backend.buildWorld(); - verify(factory, times(0)).addClass(AnnotatedInterface.class); + assertFalse(factory.classes.contains(AnnotatedInterface.class)); } @Test @@ -73,7 +81,105 @@ void considersClassWithCucumberContextConfigurationMetaAnnotation() { backend.loadGlue(glue, singletonList( URI.create("classpath:io/cucumber/spring/cucumbercontextconfigannotation"))); backend.buildWorld(); - verify(factory, times(1)).addClass(WithMetaAnnotation.class); + assertTrue(factory.classes.contains(WithMetaAnnotation.class)); + } + + private static class MockObjectFactory implements ObjectFactory { + List> classes = new ArrayList<>(); + boolean started = false; + boolean stopped = false; + + @Override + public boolean addClass(Class glueClass) { + return classes.add(glueClass); + } + + @Override + public T getInstance(Class glueClass) { + return null; + } + + @Override + public void start() { + started = true; + } + + @Override + public void stop() { + stopped = true; + } + } + + private static class MockGlue implements Glue { + + @Override + public void addBeforeAllHook(StaticHookDefinition beforeAllHook) { + + } + + @Override + public void addAfterAllHook(StaticHookDefinition afterAllHook) { + + } + + @Override + public void addStepDefinition(StepDefinition stepDefinition) { + + } + + @Override + public void addBeforeHook(HookDefinition beforeHook) { + + } + + @Override + public void addAfterHook(HookDefinition afterHook) { + + } + + @Override + public void addBeforeStepHook(HookDefinition beforeStepHook) { + + } + + @Override + public void addAfterStepHook(HookDefinition afterStepHook) { + + } + + @Override + public void addParameterType(ParameterTypeDefinition parameterType) { + + } + + @Override + public void addDataTableType(DataTableTypeDefinition dataTableType) { + + } + + @Override + public void addDefaultParameterTransformer(DefaultParameterTransformerDefinition defaultParameterTransformer) { + + } + + @Override + public void addDefaultDataTableEntryTransformer( + DefaultDataTableEntryTransformerDefinition defaultDataTableEntryTransformer + ) { + + } + + @Override + public void addDefaultDataTableCellTransformer( + DefaultDataTableCellTransformerDefinition defaultDataTableCellTransformer + ) { + + } + + @Override + public void addDocStringType(DocStringTypeDefinition docStringType) { + + } } } diff --git a/cucumber-spring/src/test/java/io/cucumber/spring/TestTestContextAdaptorTest.java b/cucumber-spring/src/test/java/io/cucumber/spring/TestContextAdaptorTest.java similarity index 57% rename from cucumber-spring/src/test/java/io/cucumber/spring/TestTestContextAdaptorTest.java rename to cucumber-spring/src/test/java/io/cucumber/spring/TestContextAdaptorTest.java index 72ea9c0245..2dcdc35724 100644 --- a/cucumber-spring/src/test/java/io/cucumber/spring/TestTestContextAdaptorTest.java +++ b/cucumber-spring/src/test/java/io/cucumber/spring/TestContextAdaptorTest.java @@ -3,196 +3,211 @@ import io.cucumber.core.backend.CucumberBackendException; import io.cucumber.spring.beans.BellyBean; import io.cucumber.spring.beans.DummyComponent; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.lang.NonNull; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContext; import org.springframework.test.context.TestContextManager; import org.springframework.test.context.TestExecutionListener; +import java.util.ArrayList; +import java.util.List; + import static io.cucumber.spring.TestContextAdaptor.create; import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; - -@ExtendWith(MockitoExtension.class) -public class TestTestContextAdaptorTest { - - @Mock - TestExecutionListener listener; - @AfterEach - void verifyNoMoroInteractions() { - Mockito.verifyNoMoreInteractions(listener); - } +class TestContextAdaptorTest { @Test - void invokesAllLiveCycleHooks() throws Exception { + void invokesAllLiveCycleHooks() { + MockTestExecutionListener listener = new MockTestExecutionListener(); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); adaptor.start(); - inOrder.verify(listener).beforeTestClass(any()); - inOrder.verify(listener).prepareTestInstance(any()); - inOrder.verify(listener).beforeTestMethod(any()); - inOrder.verify(listener).beforeTestExecution(any()); - + assertIterableEquals(List.of( + "beforeTestClass", + "prepareTestInstance", + "beforeTestMethod", + "beforeTestExecution"), + listener.events); + + listener.events.clear(); adaptor.stop(); - inOrder.verify(listener).afterTestExecution(any()); - inOrder.verify(listener).afterTestMethod(any()); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestExecution", + "afterTestMethod", + "afterTestClass"), + listener.events); } @Test - void invokesAfterClassIfBeforeClassFailed() throws Exception { + void invokesAfterClassIfBeforeClassFailed() { + MockTestExecutionListener listener = new MockTestExecutionListener("beforeTestClass"); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); - - doThrow(new RuntimeException()).when(listener).beforeTestClass(any()); assertThrows(CucumberBackendException.class, adaptor::start); - inOrder.verify(listener).beforeTestClass(any()); + assertIterableEquals(List.of( + "beforeTestClass"), + listener.events); + listener.events.clear(); adaptor.stop(); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestClass"), + listener.events); } @Test - void invokesAfterClassIfPrepareTestInstanceFailed() throws Exception { + void invokesAfterClassIfPrepareTestInstanceFailed() { + MockTestExecutionListener listener = new MockTestExecutionListener("prepareTestInstance"); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); - - doThrow(new RuntimeException()).when(listener).prepareTestInstance(any()); assertThrows(CucumberBackendException.class, adaptor::start); - inOrder.verify(listener).beforeTestClass(any()); + assertIterableEquals(List.of( + "beforeTestClass", + "prepareTestInstance"), + listener.events); + listener.events.clear(); adaptor.stop(); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestClass"), + listener.events); } @Test - void invokesAfterMethodIfBeforeMethodThrows() throws Exception { + void invokesAfterMethodIfBeforeMethodThrows() { + MockTestExecutionListener listener = new MockTestExecutionListener("beforeTestMethod"); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); - - doThrow(new RuntimeException()).when(listener).beforeTestMethod(any()); assertThrows(CucumberBackendException.class, adaptor::start); - inOrder.verify(listener).beforeTestClass(any()); - inOrder.verify(listener).prepareTestInstance(any()); - inOrder.verify(listener).beforeTestMethod(any()); + assertIterableEquals(List.of( + "beforeTestClass", + "prepareTestInstance", + "beforeTestMethod"), + listener.events); + listener.events.clear(); adaptor.stop(); - inOrder.verify(listener).afterTestMethod(any()); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestMethod", + "afterTestClass"), + listener.events); } @Test - void invokesAfterTestExecutionIfBeforeTestExecutionThrows() throws Exception { + void invokesAfterTestExecutionIfBeforeTestExecutionThrows() { + MockTestExecutionListener listener = new MockTestExecutionListener("beforeTestExecution"); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); - - doThrow(new RuntimeException()).when(listener).beforeTestExecution(any()); assertThrows(CucumberBackendException.class, adaptor::start); - inOrder.verify(listener).beforeTestClass(any()); - inOrder.verify(listener).prepareTestInstance(any()); - inOrder.verify(listener).beforeTestMethod(any()); - + assertIterableEquals(List.of( + "beforeTestClass", + "prepareTestInstance", + "beforeTestMethod", + "beforeTestExecution"), + listener.events); + + listener.events.clear(); adaptor.stop(); - inOrder.verify(listener).afterTestExecution(any()); - inOrder.verify(listener).afterTestMethod(any()); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestExecution", + "afterTestMethod", + "afterTestClass"), + listener.events); } @Test - void invokesAfterTestMethodIfAfterTestExecutionThrows() throws Exception { + void invokesAfterTestMethodIfAfterTestExecutionThrows() { + MockTestExecutionListener listener = new MockTestExecutionListener("afterTestExecution"); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); - - doThrow(new RuntimeException()).when(listener).afterTestExecution(any()); adaptor.start(); - inOrder.verify(listener).beforeTestClass(any()); - inOrder.verify(listener).prepareTestInstance(any()); - inOrder.verify(listener).beforeTestMethod(any()); - inOrder.verify(listener).beforeTestExecution(any()); - + assertIterableEquals(List.of( + "beforeTestClass", + "prepareTestInstance", + "beforeTestMethod", + "beforeTestExecution"), + listener.events); + + listener.events.clear(); assertThrows(CucumberBackendException.class, adaptor::stop); - inOrder.verify(listener).afterTestExecution(any()); - inOrder.verify(listener).afterTestMethod(any()); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestExecution", + "afterTestMethod", + "afterTestClass"), + listener.events); } @Test void invokesAfterTesClassIfAfterTestMethodThrows() throws Exception { + MockTestExecutionListener listener = new MockTestExecutionListener("afterTestMethod"); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); - - doThrow(new RuntimeException()).when(listener).afterTestMethod(any()); adaptor.start(); - inOrder.verify(listener).beforeTestClass(any()); - inOrder.verify(listener).prepareTestInstance(any()); - inOrder.verify(listener).beforeTestMethod(any()); - inOrder.verify(listener).beforeTestExecution(any()); - + assertIterableEquals(List.of( + "beforeTestClass", + "prepareTestInstance", + "beforeTestMethod", + "beforeTestExecution"), + listener.events); + + listener.events.clear(); assertThrows(CucumberBackendException.class, adaptor::stop); - inOrder.verify(listener).afterTestExecution(any()); - inOrder.verify(listener).afterTestMethod(any()); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestExecution", + "afterTestMethod", + "afterTestClass"), + listener.events); } @Test - void invokesAllMethodsPriorIfAfterTestClassThrows() throws Exception { + void invokesAllMethodsPriorIfAfterTestClassThrows() { + MockTestExecutionListener listener = new MockTestExecutionListener("afterTestExecution"); TestContextManager manager = new TestContextManager(SomeContextConfiguration.class); TestContextAdaptor adaptor = create(() -> manager, singletonList(SomeContextConfiguration.class)); manager.registerTestExecutionListeners(listener); - InOrder inOrder = inOrder(listener); - - doThrow(new RuntimeException()).when(listener).afterTestExecution(any()); adaptor.start(); - inOrder.verify(listener).beforeTestClass(any()); - inOrder.verify(listener).prepareTestInstance(any()); - inOrder.verify(listener).beforeTestMethod(any()); - inOrder.verify(listener).beforeTestExecution(any()); - + assertIterableEquals(List.of( + "beforeTestClass", + "prepareTestInstance", + "beforeTestMethod", + "beforeTestExecution"), + listener.events); + + listener.events.clear(); assertThrows(CucumberBackendException.class, adaptor::stop); - inOrder.verify(listener).afterTestExecution(any()); - inOrder.verify(listener).afterTestMethod(any()); - inOrder.verify(listener).afterTestClass(any()); + assertIterableEquals(List.of( + "afterTestExecution", + "afterTestMethod", + "afterTestClass"), + listener.events); } @ParameterizedTest @@ -316,4 +331,54 @@ public DummyComponent getDummyComponent() { } } + private static class MockTestExecutionListener implements TestExecutionListener { + private final List eventsThrowingExceptions; + List events = new ArrayList<>(); + + public MockTestExecutionListener(String... eventsThrowingExceptions) { + this.eventsThrowingExceptions = List.of(eventsThrowingExceptions); + } + + private void addEvent(String eventName) { + events.add(eventName); + if (eventsThrowingExceptions.contains(eventName)) { + throw new RuntimeException(eventName); + } + } + + @Override + public void beforeTestClass(TestContext testContext) { + addEvent("beforeTestClass"); + } + + @Override + public void prepareTestInstance(TestContext testContext) { + addEvent("prepareTestInstance"); + } + + @Override + public void beforeTestMethod(TestContext testContext) { + addEvent("beforeTestMethod"); + } + + @Override + public void beforeTestExecution(TestContext testContext) { + addEvent("beforeTestExecution"); + } + + @Override + public void afterTestExecution(TestContext testContext) { + addEvent("afterTestExecution"); + } + + @Override + public void afterTestMethod(TestContext testContext) { + addEvent("afterTestMethod"); + } + + @Override + public void afterTestClass(TestContext testContext) { + addEvent("afterTestClass"); + } + } } diff --git a/cucumber-testng/pom.xml b/cucumber-testng/pom.xml index 932e662a63..fc36ba85ea 100644 --- a/cucumber-testng/pom.xml +++ b/cucumber-testng/pom.xml @@ -16,7 +16,6 @@ 3.0 7.10.2 1.1.2 - 5.14.2 @@ -47,12 +46,6 @@ testng ${testng.version} - - org.mockito - mockito-core - ${mockito.version} - test - org.hamcrest hamcrest diff --git a/cucumber-testng/src/test/java/io/cucumber/testng/TestCaseResultObserverTest.java b/cucumber-testng/src/test/java/io/cucumber/testng/TestCaseResultObserverTest.java index 7bdbd79844..7c8070e048 100644 --- a/cucumber-testng/src/test/java/io/cucumber/testng/TestCaseResultObserverTest.java +++ b/cucumber-testng/src/test/java/io/cucumber/testng/TestCaseResultObserverTest.java @@ -2,6 +2,7 @@ import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.runtime.TimeServiceEventBus; +import io.cucumber.plugin.event.Argument; import io.cucumber.plugin.event.Location; import io.cucumber.plugin.event.PickleStepTestStep; import io.cucumber.plugin.event.Result; @@ -9,14 +10,17 @@ import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion; import io.cucumber.plugin.event.Status; import io.cucumber.plugin.event.Step; +import io.cucumber.plugin.event.StepArgument; import io.cucumber.plugin.event.TestCase; import io.cucumber.plugin.event.TestCaseFinished; +import io.cucumber.plugin.event.TestStep; import io.cucumber.plugin.event.TestStepFinished; import org.testng.SkipException; import org.testng.annotations.Test; import java.net.URI; import java.time.Clock; +import java.util.List; import java.util.UUID; import static io.cucumber.plugin.event.Status.AMBIGUOUS; @@ -31,8 +35,6 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.expectThrows; @@ -43,16 +45,11 @@ public class TestCaseResultObserverTest { private final URI uri = URI.create("file:path/to.feature"); private final Location location = new Location(0, -1); private final Exception error = new Exception(); - private final TestCase testCase = mock(TestCase.class); + private final TestCase testCase = new MockTestCase(); private final PickleStepTestStep step = createPickleStepTestStep(); private PickleStepTestStep createPickleStepTestStep() { - PickleStepTestStep testStep = mock(PickleStepTestStep.class); - Step step = mock(Step.class); - when(step.getLocation()).thenReturn(location); - when(testStep.getStep()).thenReturn(step); - when(testStep.getUri()).thenReturn(uri); - return testStep; + return new MockPickleStepTestStep(new MockStep(location), uri); } @Test @@ -200,4 +197,138 @@ public void should_be_skipped_for_skipped_result() { assertThat(exception.getCause(), instanceOf(SkipException.class)); } + private static final class MockStep implements Step { + Location location; + public MockStep(Location location) { + this.location = location; + } + + @Override + public StepArgument getArgument() { + return null; + } + + @Override + public String getKeyword() { + return null; + } + + @Override + public String getText() { + return null; + } + + @Override + public int getLine() { + return 0; + } + + @Override + public Location getLocation() { + return location; + } + } + + private static class MockPickleStepTestStep implements PickleStepTestStep { + private final Step step; + private final URI uri; + + public MockPickleStepTestStep(Step step, URI uri) { + this.step = step; + this.uri = uri; + } + + @Override + public String getPattern() { + return null; + } + + @Override + public Step getStep() { + return step; + } + + @Override + public List getDefinitionArgument() { + return null; + } + + @Override + public StepArgument getStepArgument() { + return null; + } + + @Override + public int getStepLine() { + return 0; + } + + @Override + public URI getUri() { + return uri; + } + + @Override + public String getStepText() { + return null; + } + + @Override + public String getCodeLocation() { + return null; + } + + @Override + public UUID getId() { + return null; + } + } + + private static class MockTestCase implements TestCase { + + @Override + public Integer getLine() { + return null; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getKeyword() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getScenarioDesignation() { + return null; + } + + @Override + public List getTags() { + return null; + } + + @Override + public List getTestSteps() { + return null; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public UUID getId() { + return null; + } + } } diff --git a/datatable/pom.xml b/datatable/pom.xml index f12a1ce115..35cde460e1 100644 --- a/datatable/pom.xml +++ b/datatable/pom.xml @@ -20,7 +20,6 @@ 3.0 2.18.0 5.11.2 - 5.14.2 @@ -75,13 +74,6 @@ test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - - com.google.guava guava