From b537c6c78431ce0600c04c6f2b957e3289d28724 Mon Sep 17 00:00:00 2001 From: Gintautas Miselis Date: Tue, 27 Dec 2022 22:08:57 +0200 Subject: [PATCH] Stop using __mocked field in objects created by Stub library --- composer.json | 2 +- src/Codeception/Step.php | 20 +++++++- tests/data/DummyOverloadableClass.php | 10 ++-- tests/unit/Codeception/StepTest.php | 74 ++++++++++++++++++--------- 4 files changed, 71 insertions(+), 35 deletions(-) diff --git a/composer.json b/composer.json index 20cebcb153..8d87803379 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "ext-mbstring": "*", "behat/gherkin": "^4.6.2", "codeception/lib-asserts": "2.0.*@dev", - "codeception/stub": "^3.7 | ^4.0", + "codeception/stub": "^4.1", "phpunit/phpunit": "^9.5", "phpunit/php-code-coverage": "^9.2", "phpunit/php-text-template": "^2.0", diff --git a/src/Codeception/Step.php b/src/Codeception/Step.php index eb960d8f28..8d943400dd 100644 --- a/src/Codeception/Step.php +++ b/src/Codeception/Step.php @@ -185,8 +185,24 @@ protected function getClassName(object $argument): string { if ($argument instanceof Closure) { return Closure::class; - } elseif ($argument instanceof MockObject && (property_exists($argument, '__mocked') && $argument->__mocked !== null)) { - return $this->formatClassName($argument->__mocked); + } elseif ($argument instanceof MockObject) { + $parentClass = get_parent_class($argument); + $reflection = new \ReflectionClass($argument); + + if ($parentClass !== false) { + return $this->formatClassName($parentClass); + } + + $interfaces = $reflection->getInterfaceNames(); + foreach ($interfaces as $interface) { + if (str_starts_with($interface, 'PHPUnit\\')) { + continue; + } + if (str_starts_with($interface, 'Codeception\\')) { + continue; + } + return $this->formatClassName($interface); + } } return $this->formatClassName($argument::class); diff --git a/tests/data/DummyOverloadableClass.php b/tests/data/DummyOverloadableClass.php index 04127d0564..cff44a34bf 100644 --- a/tests/data/DummyOverloadableClass.php +++ b/tests/data/DummyOverloadableClass.php @@ -57,15 +57,11 @@ public function exceptionalMethod(): void public function __get($name) { - //seeing as we're not implementing __set here, add check for __mocked - $return = null; - if ($name === '__mocked') { - $return = $this->__mocked ?? null; - } elseif ($this->__isset($name)) { - $return = $this->properties[$name]; + if ($this->__isset($name)) { + return $this->properties[$name]; } - return $return; + return null; } public function __isset($name) diff --git a/tests/unit/Codeception/StepTest.php b/tests/unit/Codeception/StepTest.php index cd7f640544..c802029f7d 100644 --- a/tests/unit/Codeception/StepTest.php +++ b/tests/unit/Codeception/StepTest.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Codeception\Command\Shared\ConfigTrait; use Codeception\Step; use Codeception\Step\Argument\FormattedOutput; use Codeception\Stub; @@ -18,33 +19,56 @@ protected function getStep(array $args): Step ->getMock(); } - public function testGetArguments() + /** + * @dataProvider getArgumentsDataProvider + */ + public function testGetArguments(array $arguments, string $expectedOutput) { - //facebook/php-webdriver is no longer a dependency of core so this behaviour can't be tested anymore - //$by = WebDriverBy::cssSelector('.something'); - //$step = $this->getStep(['', [$by]]); - //$this->assertSame('"' . Locator::humanReadableString($by) . '"', $step->getArgumentsAsString()); - - $step = $this->getStep(['', [['just', 'array']]]); - $this->assertSame('["just","array"]', $step->getArgumentsAsString()); - - $step = $this->getStep(['', [function () { - }]]); - $this->assertSame('"Closure"', $step->getArgumentsAsString()); - - $step = $this->getStep(['', [[$this, 'testGetArguments']]]); - $this->assertSame('["StepTest","testGetArguments"]', $step->getArgumentsAsString()); - - $step = $this->getStep(['', [[PDO::class, 'getAvailableDrivers']]]); - $this->assertSame('["PDO","getAvailableDrivers"]', $step->getArgumentsAsString()); - - $step = $this->getStep(['', [[Stub::make($this, []), 'testGetArguments']]]); - $this->assertSame('["StepTest","testGetArguments"]', $step->getArgumentsAsString()); + $step = $this->getStep(['', $arguments]); + $this->assertSame($expectedOutput, $step->getArgumentsAsString()); + } - $mock = $this->createMock($this::class); - $step = $this->getStep(['', [[$mock, 'testGetArguments']]]); - $className = $mock::class; - $this->assertSame('["' . $className . '","testGetArguments"]', $step->getArgumentsAsString()); + protected function getArgumentsDataProvider(): array + { + $mockGenerator = new \PHPUnit\Framework\MockObject\Generator(); + $traitMock = $mockGenerator->getMockForTrait(_generated\CodeGuyActions::class); + $classMock = $mockGenerator->getMock($this::class); + + return [ + 'scalar arguments' => [ + [['just', 'array']], + '["just","array"]', + ], + 'closure' => [ + [function () { + }], + '"Closure"', + ], + 'instance method' => [ + [[$this, 'testGetArguments']], + '["StepTest","testGetArguments"]', + ], + 'class method' => [ + [[PDO::class, 'getAvailableDrivers']], + '["PDO","getAvailableDrivers"]', + ], + 'stubbed class method' => [ + [[Stub::make($this, []), 'testGetArguments']], + '["StepTest","testGetArguments"]', + ], + 'stubbed interface method' => [ + [[Stub::makeEmpty(Countable::class, []), 'testGetArguments']], + '["Countable","testGetArguments"]', + ], + 'mocked trait method' => [ + [[$traitMock, 'testGetArguments']], + '["' . get_parent_class($traitMock) . '","testGetArguments"]', + ], + 'mocked class method' => [ + [[$classMock, 'testGetArguments']], + '["StepTest","testGetArguments"]', + ], + ]; } public function testGetHtml()