diff --git a/README.md b/README.md index 5c3251e..ae6ee86 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,47 @@ public function giveBananaToGorilla($monkey, $scenarioBanana, Bonobo $bonobo) } ``` +### Using state fragments in Behat hook methods + +It's also possible to consume state fragments in hook methods: `BeforeScenario` & `AfterScenario`. And much better, +the order is not important, you can set your arguments in any order you want: + +```php +use Behat\Behat\Hook\Scope\AfterScenarioScope; +use Behat\Behat\Hook\Scope\BeforeScenarioScope; +use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; + +/** + * @BeforeScenario + * + * @ScenarioStateArgument("scenarioBanana") + * + * @param string $scenarioBanana + * @param BeforeScenarioScope $scope + */ +public function checkBananaBeforeScenario($scenarioBanana, BeforeScenarioScope $scope) +{ + // (note that PHPUnit is here only given as an example, feel free to use any asserter you want) + \PHPUnit_Framework_Assert::assertEquals($scenarioBanana, 'Yammy Banana'); + \PHPUnit_Framework_Assert::assertNotNull($scope); +} + +/** + * @AfterScenario + * + * @ScenarioStateArgument("scenarioBanana") + * + * @param string $scenarioBanana + * @param AfterScenarioScope $scope + */ +public function checkBananaAfterScenario($scenarioBanana, AfterScenarioScope $scope) +{ + // (note that PHPUnit is here only given as an example, feel free to use any asserter you want) + \PHPUnit_Framework_Assert::assertEquals($scenarioBanana, 'Yammy Banana'); + \PHPUnit_Framework_Assert::assertNotNull($scope); +} +``` + ## Why injecting state's fragments through method params 1. Clear dependencies declaration for the step method diff --git a/features/scenario_state.feature b/features/scenario_state.feature index 5593c42..9237d60 100644 --- a/features/scenario_state.feature +++ b/features/scenario_state.feature @@ -1,19 +1,16 @@ Feature: Scenario shared state - In order to statefully test a - suite of calls to a stateless - system, I need a way to store the - scenario state + In order to statefully test a suite of calls to a stateless system, I need a way to store the scenario state Scenario: Scenario state should be shared between steps When I run "behat --no-colors features/monkey.feature" Then it should pass with: - """ - 1 scenario (1 passed) - """ + """ + 1 scenario (1 passed) + """ - Scenario: Scenario state should be reseted between scenarios + Scenario: Scenario state should be reset between scenarios When I run "behat --no-colors features/donkeys.feature" Then it should fail with: - """ - [Behat\Testwork\Argument\Exception\UnknownParameterValueException] - """ + """ + [Behat\Testwork\Argument\Exception\UnknownParameterValueException] + """ diff --git a/src/ScenarioStateArgumentOrganiser.php b/src/Argument/ScenarioStateArgumentOrganiser.php similarity index 95% rename from src/ScenarioStateArgumentOrganiser.php rename to src/Argument/ScenarioStateArgumentOrganiser.php index f4d1e5f..44c057f 100644 --- a/src/ScenarioStateArgumentOrganiser.php +++ b/src/Argument/ScenarioStateArgumentOrganiser.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Gorghoa\ScenarioStateBehatExtension; +namespace Gorghoa\ScenarioStateBehatExtension\Argument; use Behat\Testwork\Argument\ArgumentOrganiser; use Doctrine\Common\Annotations\Reader; @@ -51,7 +51,7 @@ public function __construct(ArgumentOrganiser $organiser, ScenarioStateInitializ public function organiseArguments(ReflectionFunctionAbstract $function, array $match) { $i = array_slice(array_keys($match), -1, 1)[0]; - $paramsKeys = array_map(function($element) { + $paramsKeys = array_map(function ($element) { return $element->name; }, $function->getParameters()); diff --git a/src/ScenarioState/Exception/MissingStateException.php b/src/Exception/MissingStateException.php similarity index 84% rename from src/ScenarioState/Exception/MissingStateException.php rename to src/Exception/MissingStateException.php index 1e73889..e88c7b4 100644 --- a/src/ScenarioState/Exception/MissingStateException.php +++ b/src/Exception/MissingStateException.php @@ -1,4 +1,5 @@ diff --git a/src/Hook/Dispatcher/ScenarioStateHookDispatcher.php b/src/Hook/Dispatcher/ScenarioStateHookDispatcher.php new file mode 100644 index 0000000..727869b --- /dev/null +++ b/src/Hook/Dispatcher/ScenarioStateHookDispatcher.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\ScenarioStateBehatExtension\Hook\Dispatcher; + +use Behat\Testwork\Call\CallCenter; +use Behat\Testwork\Call\CallResults; +use Behat\Testwork\Environment\Call\EnvironmentCall; +use Behat\Testwork\Hook\Call\HookCall; +use Behat\Testwork\Hook\HookRepository; +use Behat\Testwork\Hook\Scope\HookScope; +use Doctrine\Common\Annotations\Reader; +use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; +use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; + +/** + * @author Vincent Chalamon + */ +class ScenarioStateHookDispatcher +{ + /** + * @var HookRepository + */ + private $repository; + + /** + * @var CallCenter + */ + private $callCenter; + + /** + * @var Reader + */ + private $reader; + + /** + * @var ScenarioStateInitializer + */ + private $store; + + /** + * Initializes scenario state hook dispatcher. + * + * @param HookRepository $repository + * @param CallCenter $callCenter + * @param ScenarioStateInitializer $store + * @param Reader $reader + */ + public function __construct(HookRepository $repository, CallCenter $callCenter, ScenarioStateInitializer $store, Reader $reader) + { + $this->repository = $repository; + $this->callCenter = $callCenter; + $this->reader = $reader; + $this->store = $store; + } + + /** + * Dispatches hooks for a specified event. + * + * @param HookScope $scope + * + * @return CallResults + */ + public function dispatchScopeHooks(HookScope $scope) + { + $results = []; + foreach ($this->repository->getScopeHooks($scope) as $hook) { + /** @var \ReflectionMethod $function */ + $function = $hook->getReflection(); + + // No `@ScenarioStateArgument` annotation found + if (null === $this->reader->getMethodAnnotation($function, ScenarioStateArgument::class)) { + $results[] = $this->callCenter->makeCall(new HookCall($scope, $hook)); + continue; + } + + $paramsKeys = array_map(function ($element) { + return $element->name; + }, $function->getParameters()); + $store = $this->store->getStore(); + $params = $arguments = []; + + // Prepare arguments from annotations + /** @var ScenarioStateArgument[] $annotations */ + $annotations = $this->reader->getMethodAnnotations($function); + foreach ($annotations as $annotation) { + if ($annotation instanceof ScenarioStateArgument && + in_array($annotation->getArgument(), $paramsKeys) && + $store->hasStateFragment($annotation->getName()) + ) { + $params[$annotation->getArgument()] = $store->getStateFragment($annotation->getName()); + } + } + + // Manage `scope` argument + foreach ($function->getParameters() as $parameter) { + if (null !== $parameter->getClass() && get_class($scope) === $parameter->getClass()->getName()) { + $arguments[$parameter->getName()] = $scope; + } elseif (isset($params[$parameter->getName()])) { + $arguments[$parameter->getName()] = $params[$parameter->getName()]; + } + } + + $results[] = $this->callCenter->makeCall(new EnvironmentCall($scope->getEnvironment(), $hook, $arguments)); + } + + return new CallResults($results); + } +} diff --git a/src/Hook/Tester/ScenarioStateHookableScenarioTester.php b/src/Hook/Tester/ScenarioStateHookableScenarioTester.php new file mode 100644 index 0000000..77efee9 --- /dev/null +++ b/src/Hook/Tester/ScenarioStateHookableScenarioTester.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\ScenarioStateBehatExtension\Hook\Tester; + +use Behat\Behat\Hook\Scope\AfterScenarioScope; +use Behat\Behat\Hook\Scope\BeforeScenarioScope; +use Behat\Behat\Tester\ScenarioTester; +use Behat\Gherkin\Node\FeatureNode; +use Behat\Gherkin\Node\ScenarioInterface as Scenario; +use Behat\Testwork\Environment\Environment; +use Behat\Testwork\Hook\Tester\Setup\HookedSetup; +use Behat\Testwork\Hook\Tester\Setup\HookedTeardown; +use Behat\Testwork\Tester\Result\TestResult; +use Gorghoa\ScenarioStateBehatExtension\Hook\Dispatcher\ScenarioStateHookDispatcher; + +/** + * @author Vincent Chalamon + */ +final class ScenarioStateHookableScenarioTester implements ScenarioTester +{ + /** + * @var ScenarioTester + */ + private $baseTester; + + /** + * @var ScenarioStateHookDispatcher + */ + private $dispatcher; + + /** + * @param ScenarioTester $baseTester + * @param ScenarioStateHookDispatcher $dispatcher + */ + public function __construct(ScenarioTester $baseTester, ScenarioStateHookDispatcher $dispatcher) + { + $this->baseTester = $baseTester; + $this->dispatcher = $dispatcher; + } + + /** + * {@inheritdoc} + */ + public function setUp(Environment $env, FeatureNode $feature, Scenario $scenario, $skip) + { + $setup = $this->baseTester->setUp($env, $feature, $scenario, true); + + if ($skip) { + return $setup; + } + + return new HookedSetup($setup, $this->dispatcher->dispatchScopeHooks(new BeforeScenarioScope($env, $feature, $scenario))); + } + + /** + * {@inheritdoc} + */ + public function test(Environment $env, FeatureNode $feature, Scenario $scenario, $skip) + { + return $this->baseTester->test($env, $feature, $scenario, $skip); + } + + /** + * {@inheritdoc} + */ + public function tearDown(Environment $env, FeatureNode $feature, Scenario $scenario, $skip, TestResult $result) + { + $teardown = $this->baseTester->tearDown($env, $feature, $scenario, true, $result); + + if ($skip) { + return $teardown; + } + + return new HookedTeardown($teardown, $this->dispatcher->dispatchScopeHooks(new AfterScenarioScope($env, $feature, $scenario, $result))); + } +} diff --git a/src/ScenarioState.php b/src/ScenarioState.php index 905aff2..9258139 100644 --- a/src/ScenarioState.php +++ b/src/ScenarioState.php @@ -11,7 +11,7 @@ namespace Gorghoa\ScenarioStateBehatExtension; -use Gorghoa\ScenarioStateBehatExtension\ScenarioState\Exception\MissingStateException; +use Gorghoa\ScenarioStateBehatExtension\Exception\MissingStateException; /** * @author Rodrigue Villetard diff --git a/src/ScenarioStateInterface.php b/src/ScenarioStateInterface.php index 3347ddb..780b51d 100644 --- a/src/ScenarioStateInterface.php +++ b/src/ScenarioStateInterface.php @@ -10,7 +10,8 @@ */ namespace Gorghoa\ScenarioStateBehatExtension; -use Gorghoa\ScenarioStateBehatExtension\ScenarioState\Exception\MissingStateException; + +use Gorghoa\ScenarioStateBehatExtension\Exception\MissingStateException; /** * @author Rodrigue Villetard diff --git a/src/ServiceContainer/ScenarioStateExtension.php b/src/ServiceContainer/ScenarioStateExtension.php index 1408f8d..64114d5 100644 --- a/src/ServiceContainer/ScenarioStateExtension.php +++ b/src/ServiceContainer/ScenarioStateExtension.php @@ -12,17 +12,21 @@ namespace Gorghoa\ScenarioStateBehatExtension\ServiceContainer; use Behat\Behat\Context\ServiceContainer\ContextExtension; +use Behat\Behat\Tester\ServiceContainer\TesterExtension; use Behat\Testwork\Argument\ServiceContainer\ArgumentExtension; +use Behat\Testwork\Call\ServiceContainer\CallExtension; use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension; +use Behat\Testwork\Hook\ServiceContainer\HookExtension; use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface; use Behat\Testwork\ServiceContainer\ExtensionManager; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\AnnotationRegistry; +use Gorghoa\ScenarioStateBehatExtension\Argument\ScenarioStateArgumentOrganiser; use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; -use Gorghoa\ScenarioStateBehatExtension\ScenarioStateArgumentOrganiser; +use Gorghoa\ScenarioStateBehatExtension\Hook\Dispatcher\ScenarioStateHookDispatcher; +use Gorghoa\ScenarioStateBehatExtension\Hook\Tester\ScenarioStateHookableScenarioTester; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; /** @@ -33,7 +37,9 @@ */ class ScenarioStateExtension implements ExtensionInterface { - const SCENARIO_STATE_ARGUMENT_ORGANISER_ID = 'argument.scenario_state_organiser'; + const SCENARIO_STATE_ARGUMENT_ORGANISER_ID = 'argument.scenario_state.organiser'; + const SCENARIO_STATE_DISPATCHER_ID = 'hook.scenario_state.dispatcher'; + const SCENARIO_STATE_TESTER_ID = 'tester.scenario_state.wrapper'; /** * {@inheritdoc} @@ -76,11 +82,9 @@ public function process(ContainerBuilder $container) private function loadContextInitializer(ContainerBuilder $container) { - $definition = new Definition(ScenarioStateInitializer::class, []); - $definition->addTag(ContextExtension::INITIALIZER_TAG, ['priority' => 0]); - $definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, ['priority' => 0]); - - $container->setDefinition('behatstore.context_initializer.store_aware', $definition); + $container->register('behatstore.context_initializer.store_aware', ScenarioStateInitializer::class) + ->addTag(ContextExtension::INITIALIZER_TAG, ['priority' => 0]) + ->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, ['priority' => 0]); } private function loadOrganiser(ContainerBuilder $container) @@ -90,7 +94,9 @@ private function loadOrganiser(ContainerBuilder $container) // Ignore Behat annotations in reader ->addMethodCall('addGlobalIgnoredName', ['Given']) ->addMethodCall('addGlobalIgnoredName', ['When']) - ->addMethodCall('addGlobalIgnoredName', ['Then']); + ->addMethodCall('addGlobalIgnoredName', ['Then']) + ->addMethodCall('addGlobalIgnoredName', ['BeforeScenario']) + ->addMethodCall('addGlobalIgnoredName', ['AfterScenario']); $container->register(self::SCENARIO_STATE_ARGUMENT_ORGANISER_ID, ScenarioStateArgumentOrganiser::class) ->setDecoratedService(ArgumentExtension::PREG_MATCH_ARGUMENT_ORGANISER_ID) @@ -100,5 +106,21 @@ private function loadOrganiser(ContainerBuilder $container) new Reference('behatstore.context_initializer.store_aware'), new Reference('doctrine.reader.annotation'), ]); + + // Override hook process + $container->register(self::SCENARIO_STATE_DISPATCHER_ID, ScenarioStateHookDispatcher::class) + ->setPublic(false) + ->setArguments([ + new Reference(HookExtension::REPOSITORY_ID), + new Reference(CallExtension::CALL_CENTER_ID), + new Reference('behatstore.context_initializer.store_aware'), + new Reference('doctrine.reader.annotation'), + ]); + $container->register(self::SCENARIO_STATE_TESTER_ID, ScenarioStateHookableScenarioTester::class) + ->setDecoratedService(TesterExtension::SCENARIO_TESTER_WRAPPER_TAG.'.hookable') + ->setArguments([ + new Reference(self::SCENARIO_STATE_TESTER_ID.'.inner'), + new Reference(self::SCENARIO_STATE_DISPATCHER_ID), + ]); } } diff --git a/testapp/features/bootstrap/FeatureContext.php b/testapp/features/bootstrap/FeatureContext.php index 796a838..65b33a4 100644 --- a/testapp/features/bootstrap/FeatureContext.php +++ b/testapp/features/bootstrap/FeatureContext.php @@ -9,6 +9,8 @@ * file that was distributed with this source code. */ +use Behat\Behat\Hook\Scope\AfterScenarioScope; +use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; use Gorghoa\ScenarioStateBehatExtension\Context\ScenarioStateAwareContext; use Gorghoa\ScenarioStateBehatExtension\ScenarioStateInterface; @@ -40,6 +42,86 @@ public function setScenarioState(ScenarioStateInterface $scenarioState) $this->scenarioState = $scenarioState; } + /** + * @BeforeScenario + */ + public function initBananas() + { + $this->scenarioState->provideStateFragment('bananas', ['foo', 'bar']); + } + + /** + * @BeforeScenario + * + * @ScenarioStateArgument("bananas") + * + * @param array $bananas + */ + public function saveBananasWithoutScopeBeforeScenario(array $bananas) + { + \PHPUnit_Framework_Assert::assertEquals(['foo', 'bar'], $bananas); + } + + /** + * @BeforeScenario + * + * @ScenarioStateArgument("bananas") + * + * @param BeforeScenarioScope $scope + * @param array $bananas + */ + public function saveBananasWithScopeBeforeScenario(BeforeScenarioScope $scope, array $bananas) + { + \PHPUnit_Framework_Assert::assertNotNull($scope); + \PHPUnit_Framework_Assert::assertEquals(['foo', 'bar'], $bananas); + } + + /** + * @BeforeScenario + * + * @param BeforeScenarioScope $scope + */ + public function initApplesBeforeScenario(BeforeScenarioScope $scope) + { + \PHPUnit_Framework_Assert::assertNotNull($scope); + } + + /** + * @AfterScenario + * + * @ScenarioStateArgument("bananas") + * + * @param array $bananas + */ + public function saveBananasWithoutScopeAfterScenario(array $bananas) + { + \PHPUnit_Framework_Assert::assertEquals(['foo', 'bar'], $bananas); + } + + /** + * @AfterScenario + * + * @ScenarioStateArgument("bananas") + * + * @param array $bananas + * @param AfterScenarioScope $scope + */ + public function saveBananasWithScopeAfterScenario(array $bananas, AfterScenarioScope $scope) + { + \PHPUnit_Framework_Assert::assertNotNull($scope); + \PHPUnit_Framework_Assert::assertEquals(['foo', 'bar'], $bananas); + } + + /** + * @AfterScenario + * + * @param AfterScenarioScope $scope + */ + public function initApplesAfterScenario(AfterScenarioScope $scope) + { + \PHPUnit_Framework_Assert::assertNotNull($scope); + } + /** * @When the bonobo takes a banana */ @@ -57,7 +139,7 @@ public function takeBanana() */ public function giveBananaToGorilla($scenarioBanana) { - \PHPUnit_Framework_Assert::assertEquals($scenarioBanana, 'Yammy Banana'); + \PHPUnit_Framework_Assert::assertEquals('Yammy Banana', $scenarioBanana); $gorilla = new Gorilla(); $gorilla->setBanana($scenarioBanana); $this->scenarioState->provideStateFragment('scenarioGorilla', $gorilla); @@ -74,7 +156,7 @@ public function giveBananaToGorilla($scenarioBanana) */ public function gorillaHasBanana($scenarioBanana, Gorilla $gorilla) { - \PHPUnit_Framework_Assert::assertEquals($scenarioBanana, 'Yammy Banana'); - \PHPUnit_Framework_Assert::assertEquals($gorilla->getBanana(), 'Yammy Banana'); + \PHPUnit_Framework_Assert::assertEquals('Yammy Banana', $scenarioBanana); + \PHPUnit_Framework_Assert::assertEquals('Yammy Banana', $gorilla->getBanana()); } } diff --git a/tests/ScenarioStateArgumentOrganiserTest.php b/tests/Argument/ScenarioStateArgumentOrganiserTest.php similarity index 97% rename from tests/ScenarioStateArgumentOrganiserTest.php rename to tests/Argument/ScenarioStateArgumentOrganiserTest.php index b7dd74f..a5a30e9 100644 --- a/tests/ScenarioStateArgumentOrganiserTest.php +++ b/tests/Argument/ScenarioStateArgumentOrganiserTest.php @@ -9,12 +9,13 @@ * file that was distributed with this source code. */ -namespace Gorghoa\ScenarioStateBehatExtension; +namespace Gorghoa\ScenarioStateBehatExtension\Argument; use Behat\Testwork\Argument\ArgumentOrganiser; use Doctrine\Common\Annotations\Reader; use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; +use Gorghoa\ScenarioStateBehatExtension\ScenarioStateInterface; use Prophecy\Prophecy\ObjectProphecy; /** diff --git a/tests/Context/Initializer/ScenarioStateInitializerTest.php b/tests/Context/Initializer/ScenarioStateInitializerTest.php new file mode 100644 index 0000000..d0202f1 --- /dev/null +++ b/tests/Context/Initializer/ScenarioStateInitializerTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\ScenarioStateBehatExtension\Context\Initializer; + +use Behat\Behat\EventDispatcher\Event\ScenarioTested; +use Gorghoa\ScenarioStateBehatExtension\Context\ScenarioStateAwareContext; +use Gorghoa\ScenarioStateBehatExtension\ScenarioState; +use Prophecy\Argument; + +/** + * @author Vincent Chalamon + */ +class ScenarioStateInitializerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ScenarioStateInitializer + */ + private $initializer; + + protected function setUp() + { + $this->initializer = new ScenarioStateInitializer(); + $this->assertNotNull($this->initializer->getStore()); + } + + public function testGetSubscribedEvents() + { + $this->assertEquals([ + ScenarioTested::AFTER => ['clearStore'], + ], ScenarioStateInitializer::getSubscribedEvents()); + } + + public function testInitializeContext() + { + $contextMock = $this->prophesize(ScenarioStateAwareContext::class); + $contextMock->setScenarioState(Argument::type(ScenarioState::class))->shouldBeCalledTimes(1); + $this->initializer->initializeContext($contextMock->reveal()); + } +} diff --git a/tests/Hook/Tester/ScenarioStateHookableScenarioTesterTest.php b/tests/Hook/Tester/ScenarioStateHookableScenarioTesterTest.php new file mode 100644 index 0000000..7c65b9b --- /dev/null +++ b/tests/Hook/Tester/ScenarioStateHookableScenarioTesterTest.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\ScenarioStateBehatExtension\Hook\Tester; + +use Behat\Behat\Tester\ScenarioTester; +use Behat\Gherkin\Node\FeatureNode; +use Behat\Gherkin\Node\ScenarioInterface; +use Behat\Testwork\Environment\Environment; +use Behat\Testwork\Tester\Result\TestResult; +use Behat\Testwork\Tester\Setup\Setup; +use Behat\Testwork\Tester\Setup\Teardown; +use Gorghoa\ScenarioStateBehatExtension\Hook\Dispatcher\ScenarioStateHookDispatcher; +use Prophecy\Prophecy\ObjectProphecy; + +/** + * @author Vincent Chalamon + */ +class ScenarioStateHookableScenarioTesterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ScenarioStateHookableScenarioTester + */ + private $tester; + + /** + * @var ScenarioTester|ObjectProphecy + */ + private $baseTesterMock; + + /** + * @var ScenarioStateHookDispatcher|ObjectProphecy + */ + private $dispatcherMock; + + /** + * @var Environment|ObjectProphecy + */ + private $environmentMock; + + /** + * @var FeatureNode|ObjectProphecy + */ + private $featureNodeMock; + + /** + * @var ScenarioInterface|ObjectProphecy + */ + private $scenarioMock; + + protected function setUp() + { + $this->baseTesterMock = $this->prophesize(ScenarioTester::class); + $this->dispatcherMock = $this->prophesize(ScenarioStateHookDispatcher::class); + $this->environmentMock = $this->prophesize(Environment::class); + $this->featureNodeMock = $this->prophesize(FeatureNode::class); + $this->scenarioMock = $this->prophesize(ScenarioInterface::class); + + $this->tester = new ScenarioStateHookableScenarioTester($this->baseTesterMock->reveal(), $this->dispatcherMock->reveal()); + } + + public function testSetUpSkip() + { + $setupMock = $this->prophesize(Setup::class); + $this->baseTesterMock->setUp($this->environmentMock, $this->featureNodeMock, $this->scenarioMock, true) + ->willReturn($setupMock) + ->shouldBeCalledTimes(1); + $this->assertEquals($setupMock->reveal(), $this->tester->setUp($this->environmentMock->reveal(), $this->featureNodeMock->reveal(), $this->scenarioMock->reveal(), true)); + } + + public function testTearDownSkip() + { + $tearDownMock = $this->prophesize(Teardown::class); + $testResultMock = $this->prophesize(TestResult::class); + $this->baseTesterMock->tearDown($this->environmentMock, $this->featureNodeMock, $this->scenarioMock, true, $testResultMock) + ->willReturn($tearDownMock) + ->shouldBeCalledTimes(1); + $this->assertEquals($tearDownMock->reveal(), $this->tester->tearDown($this->environmentMock->reveal(), $this->featureNodeMock->reveal(), $this->scenarioMock->reveal(), true, $testResultMock->reveal())); + } + + public function testTest() + { + $testResultMock = $this->prophesize(TestResult::class); + $this->baseTesterMock->test($this->environmentMock, $this->featureNodeMock, $this->scenarioMock, false) + ->willReturn($testResultMock) + ->shouldBeCalledTimes(1); + $this->assertEquals($testResultMock->reveal(), $this->tester->test($this->environmentMock->reveal(), $this->featureNodeMock->reveal(), $this->scenarioMock->reveal(), false)); + } +} diff --git a/tests/ScenarioStateTest.php b/tests/ScenarioStateTest.php index e7550fe..a205354 100644 --- a/tests/ScenarioStateTest.php +++ b/tests/ScenarioStateTest.php @@ -1,4 +1,5 @@