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..8f3c2267e4 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,122 @@ 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.*; + 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/StubPickleStepTestStep.java b/cucumber-core/src/test/java/io/cucumber/core/plugin/StubPickleStepTestStep.java index 63b715f9f3..e04e8c1f89 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/plugin/StubPickleStepTestStep.java +++ b/cucumber-core/src/test/java/io/cucumber/core/plugin/StubPickleStepTestStep.java @@ -9,7 +9,7 @@ import java.util.List; import java.util.UUID; -class StubPickleStepTestStep implements PickleStepTestStep { +public class StubPickleStepTestStep implements PickleStepTestStep { private final String pattern; private final String stepText; 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/HookTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/HookTest.java index 8570ab96a5..eb0f1e3055 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 @@ -46,7 +46,7 @@ class HookTest { void after_hooks_execute_before_objects_are_disposed() { Backend backend = mock(Backend.class); when(backend.getSnippet()).thenReturn(new TestSnippet()); - ObjectFactory objectFactory = mock(ObjectFactory.class); + ObjectFactory objectFactory = new StubObjectFactory(); final HookDefinition hook = mock(HookDefinition.class); when(hook.getLocation()).thenReturn("hook-location"); when(hook.getTagExpression()).thenReturn(""); @@ -71,7 +71,7 @@ void after_hooks_execute_before_objects_are_disposed() { 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); + ObjectFactory objectFactory = new StubObjectFactory(); final HookDefinition hook = mock(HookDefinition.class); when(hook.getLocation()).thenReturn("hook-location"); when(hook.getTagExpression()).thenReturn("("); @@ -90,4 +90,25 @@ 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() { + + } + } } 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..a10237e727 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 @@ -3,18 +3,12 @@ import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.feature.TestFeatureParser; import io.cucumber.core.gherkin.Feature; -import io.cucumber.plugin.event.EmbedEvent; -import io.cucumber.plugin.event.Result; -import io.cucumber.plugin.event.Status; -import io.cucumber.plugin.event.WriteEvent; +import io.cucumber.plugin.event.*; 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.Collections; -import java.util.UUID; +import java.util.*; import static io.cucumber.core.backend.Status.FAILED; import static io.cucumber.core.backend.Status.PASSED; @@ -25,13 +19,7 @@ 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.assertAll; -import static org.junit.jupiter.api.Assertions.assertFalse; -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; +import static org.junit.jupiter.api.Assertions.*; class TestCaseStateResultTest { @@ -39,7 +27,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 +41,6 @@ class TestCaseStateResultTest { @BeforeEach void setup() { - when(bus.getInstant()).thenReturn(Instant.now()); s.setCurrentTestStepId(UUID.randomUUID()); } @@ -117,21 +104,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 +135,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 +144,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..2961e5f16c 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,88 @@ package io.cucumber.core.runner; +import io.cucumber.core.backend.*; +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.TestCaseFinished; -import io.cucumber.plugin.event.TestCaseStarted; -import org.junit.jupiter.api.BeforeEach; +import io.cucumber.plugin.event.*; +import io.cucumber.plugin.event.Status; 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.*; 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())))), + singletonList( + new HookTestStep(UUID.randomUUID(), AFTER_STEP, + new HookDefinitionMatch(CoreHookDefinition.create(new StubHookDefinition())))), + 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 +99,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/runtime/RuntimeTest.java b/cucumber-core/src/test/java/io/cucumber/core/runtime/RuntimeTest.java index f7167191e8..e11051fc41 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 @@ -1,13 +1,6 @@ package io.cucumber.core.runtime; -import io.cucumber.core.backend.CucumberBackendException; -import io.cucumber.core.backend.Glue; -import io.cucumber.core.backend.HookDefinition; -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.backend.*; import io.cucumber.core.eventbus.EventBus; import io.cucumber.core.exception.CompositeCucumberException; import io.cucumber.core.exception.CucumberException; @@ -15,6 +8,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 +21,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 +29,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 +52,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 +79,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 +150,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 +159,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 +187,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 +236,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 +296,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 +474,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 +528,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 +557,7 @@ public String getLocation() { } - private static final class MockedScenarioScopedStepDefinition + private static final class StubScenarioScopedStepDefinition implements ScenarioScoped, io.cucumber.core.backend.StepDefinition { @Override @@ -650,4 +637,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-java/pom.xml b/cucumber-java/pom.xml index 645924dcf4..56a64892cc 100644 --- a/cucumber-java/pom.xml +++ b/cucumber-java/pom.xml @@ -72,12 +72,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..37b4a1ca77 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,13 @@ package io.cucumber.java; -import io.cucumber.core.backend.Glue; -import io.cucumber.core.backend.ObjectFactory; -import io.cucumber.core.backend.StepDefinition; +import io.cucumber.core.backend.*; 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 +17,43 @@ 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.assertThrows; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import static org.junit.jupiter.api.Assertions.*; -@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 +63,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 +76,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 6eb9f4b815..042041ccb7 100644 --- a/cucumber-java8/pom.xml +++ b/cucumber-java8/pom.xml @@ -71,13 +71,6 @@ test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - - org.hamcrest hamcrest-core @@ -89,7 +82,7 @@ org.freemarker freemarker 2.3.32 - test + 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 67208df755..9a55bc01e4 100644 --- a/cucumber-java8/src/test/java/io/cucumber/java8/Java8BackendTest.java +++ b/cucumber-java8/src/test/java/io/cucumber/java8/Java8BackendTest.java @@ -1,52 +1,123 @@ package io.cucumber.java8; -import io.cucumber.core.backend.Glue; -import io.cucumber.core.backend.ObjectFactory; +import io.cucumber.core.backend.*; 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.Arrays; +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 0ca4a7e678..4f22729e2b 100644 --- a/cucumber-junit/pom.xml +++ b/cucumber-junit/pom.xml @@ -64,12 +64,6 @@ junit-vintage-engine test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - org.hamcrest hamcrest-core 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..7008dbee53 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,21 @@ 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.assertThrows; -import static org.mockito.ArgumentMatchers.argThat; +import static org.junit.jupiter.api.Assertions.*; class CucumberTest { @@ -96,67 +94,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 +231,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..2e37859610 100644 --- a/cucumber-junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java +++ b/cucumber-junit/src/test/java/io/cucumber/junit/FeatureRunnerTest.java @@ -19,25 +19,18 @@ 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.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; import static java.util.Collections.singleton; 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.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; +import static org.junit.jupiter.api.Assertions.*; class FeatureRunnerTest { @@ -141,24 +134,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 +169,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 +266,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 +324,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 +371,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 +416,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..47abb1714e 100644 --- a/cucumber-junit/src/test/java/io/cucumber/junit/JUnitReporterWithStepNotificationsTest.java +++ b/cucumber-junit/src/test/java/io/cucumber/junit/JUnitReporterWithStepNotificationsTest.java @@ -6,35 +6,19 @@ 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.Location; -import io.cucumber.plugin.event.PickleStepTestStep; -import io.cucumber.plugin.event.Result; -import io.cucumber.plugin.event.SnippetsSuggestedEvent; +import io.cucumber.plugin.event.*; import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion; -import io.cucumber.plugin.event.Status; -import io.cucumber.plugin.event.TestCase; -import io.cucumber.plugin.event.TestCaseFinished; -import io.cucumber.plugin.event.TestCaseStarted; -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.List; -import java.util.UUID; +import java.util.*; import static java.time.Duration.ZERO; import static java.time.Instant.now; @@ -44,15 +28,8 @@ 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.*; + class JUnitReporterWithStepNotificationsTest { private static final Location scenarioLine = new Location(0, 0); @@ -65,47 +42,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 +71,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 +186,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 +220,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 +302,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-spring/pom.xml b/cucumber-spring/pom.xml index ed66b62355..9fb0bbc867 100644 --- a/cucumber-spring/pom.xml +++ b/cucumber-spring/pom.xml @@ -90,12 +90,6 @@ ${hamcrest.version} test - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - 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 56% 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..b34cb93908 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,205 @@ 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.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); - } +import static org.junit.jupiter.api.Assertions.*; + +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 +325,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"); + } + } }