From f0d4aee11827ab6ba8a93ce7db280f4f4e280058 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 6 Sep 2019 11:01:38 +0200 Subject: [PATCH] #3120 implemented `TestCase#createStub()` --- .../MockObject/Builder/InvocationMocker.php | 12 ++--- .../MockObject/Builder/InvocationStubber.php | 44 +++++++++++++++++++ src/Framework/MockObject/Stub.php | 4 +- src/Framework/TestCase.php | 13 ++++++ tests/static-analysis/TestUsingMocks.php | 11 +++++ tests/unit/Framework/TestCaseTest.php | 36 +++++++++++++-- 6 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 src/Framework/MockObject/Builder/InvocationStubber.php diff --git a/src/Framework/MockObject/Builder/InvocationMocker.php b/src/Framework/MockObject/Builder/InvocationMocker.php index 05f5fb577d2..914c730e9a7 100644 --- a/src/Framework/MockObject/Builder/InvocationMocker.php +++ b/src/Framework/MockObject/Builder/InvocationMocker.php @@ -29,7 +29,7 @@ /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ -final class InvocationMocker implements MethodNameMatch +final class InvocationMocker implements InvocationStubber, MethodNameMatch { /** * @var MatcherCollection @@ -68,7 +68,7 @@ public function id($id): self return $this; } - public function will(Stub $stub): Identity + public function will(Stub $stub): self { $this->matcher->setStub($stub); @@ -92,9 +92,7 @@ public function willReturn($value, ...$nextValues): self return $this->will($stub); } - /** - * @param mixed $reference - */ + /** {@inheritDoc} */ public function willReturnReference(&$reference): self { $stub = new ReturnReference($reference); @@ -116,9 +114,7 @@ public function willReturnArgument($argumentIndex): self return $this->will($stub); } - /** - * @param callable $callback - */ + /** {@inheritDoc} */ public function willReturnCallback($callback): self { $stub = new ReturnCallback($callback); diff --git a/src/Framework/MockObject/Builder/InvocationStubber.php b/src/Framework/MockObject/Builder/InvocationStubber.php new file mode 100644 index 00000000000..4acfad9f4f1 --- /dev/null +++ b/src/Framework/MockObject/Builder/InvocationStubber.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Builder; + +use PHPUnit\Framework\MockObject\Stub\Stub; + +/** @internal This class is not covered by the backward compatibility promise for PHPUnit */ +interface InvocationStubber +{ + /** + * @TODO is "will" actually sensible in a stub context? Should a stub produce side-effects? + * + * Note: probably yes, since you want a stub of a promise to be able to resolve a real callback, for example + */ + public function will(Stub $stub): Identity; + + public function willReturn($value, ...$nextValues): self; + + /** @param mixed $reference */ + public function willReturnReference(&$reference): self; + + /** @param array> $valueMap */ + public function willReturnMap(array $valueMap): self; + + /** @param int $argumentIndex */ + public function willReturnArgument($argumentIndex): self; + + /** @param callable $callback */ + public function willReturnCallback($callback): self; + + public function willReturnSelf(): self; + + /** @param mixed $values */ + public function willReturnOnConsecutiveCalls(...$values): self; + + public function willThrowException(\Throwable $exception): self; +} diff --git a/src/Framework/MockObject/Stub.php b/src/Framework/MockObject/Stub.php index e5c88274916..951885ed1f7 100644 --- a/src/Framework/MockObject/Stub.php +++ b/src/Framework/MockObject/Stub.php @@ -9,10 +9,10 @@ */ namespace PHPUnit\Framework\MockObject; -use PHPUnit\Framework\MockObject\Builder\InvocationMocker as BuilderInvocationMocker; +use PHPUnit\Framework\MockObject\Builder\InvocationStubber; /** - * @method BuilderInvocationMocker method($constraint) + * @method InvocationStubber method($constraint) */ interface Stub { diff --git a/src/Framework/TestCase.php b/src/Framework/TestCase.php index 6791df30066..f487e46db2f 100644 --- a/src/Framework/TestCase.php +++ b/src/Framework/TestCase.php @@ -27,6 +27,7 @@ use PHPUnit\Framework\MockObject\Matcher\InvokedCount as InvokedCountMatcher; use PHPUnit\Framework\MockObject\MockBuilder; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls as ConsecutiveCallsStub; use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub; use PHPUnit\Framework\MockObject\Stub\ReturnArgument as ReturnArgumentStub; @@ -1543,6 +1544,18 @@ protected function setLocale(...$args): void } } + /** + * Makes configurable stub for the specified class. + * + * @psalm-template RealInstanceType of object + * @psalm-param class-string $originalClassName + * @psalm-return Stub&RealInstanceType + */ + protected function createStub(string $originalClassName): Stub + { + return $this->createMock($originalClassName); + } + /** * Returns a test double for the specified class. * diff --git a/tests/static-analysis/TestUsingMocks.php b/tests/static-analysis/TestUsingMocks.php index 8f91d85f00d..2ed4a72394f 100644 --- a/tests/static-analysis/TestUsingMocks.php +++ b/tests/static-analysis/TestUsingMocks.php @@ -35,6 +35,17 @@ public function testWillSayHelloThroughCreateMock(): void self::assertSame('hello mock!', $mock->sayHello()); } + public function testWillSayHelloThroughCreateStub(): void + { + $mock = $this->createStub(HelloWorldClass::class); + + $mock + ->method('sayHello') + ->willReturn('hello mock!'); + + self::assertSame('hello mock!', $mock->sayHello()); + } + public function testWillSayHelloThroughCreateConfiguredMock(): void { $mock = $this->createConfiguredMock(HelloWorldClass::class, []); diff --git a/tests/unit/Framework/TestCaseTest.php b/tests/unit/Framework/TestCaseTest.php index 5108d187672..4d5ecc586ed 100644 --- a/tests/unit/Framework/TestCaseTest.php +++ b/tests/unit/Framework/TestCaseTest.php @@ -10,6 +10,7 @@ namespace PHPUnit\Framework; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub\Stub; use PHPUnit\Runner\BaseTestRunner; use PHPUnit\Util\Test as TestUtil; @@ -832,13 +833,28 @@ public function testCreateMockFromClassName(): void public function testCreateMockMocksAllMethods(): void { - /** @var \Mockable $mock */ $mock = $this->createMock(\Mockable::class); $this->assertNull($mock->mockableMethod()); $this->assertNull($mock->anotherMockableMethod()); } + public function testCreateStubFromClassName(): void + { + $mock = $this->createStub(\Mockable::class); + + $this->assertInstanceOf(\Mockable::class, $mock); + $this->assertInstanceOf(Stub::class, $mock); + } + + public function testCreateStubMocksAllMethods(): void + { + $mock = $this->createStub(\Mockable::class); + + $this->assertNull($mock->mockableMethod()); + $this->assertNull($mock->anotherMockableMethod()); + } + public function testCreatePartialMockDoesNotMockAllMethods(): void { /** @var \Mockable $mock */ @@ -879,7 +895,6 @@ public function testCreatePartialMockWithRealMethods(): void public function testCreateMockSkipsConstructor(): void { - /** @var \Mockable $mock */ $mock = $this->createMock(\Mockable::class); $this->assertNull($mock->constructorArgs); @@ -887,13 +902,27 @@ public function testCreateMockSkipsConstructor(): void public function testCreateMockDisablesOriginalClone(): void { - /** @var \Mockable $mock */ $mock = $this->createMock(\Mockable::class); $cloned = clone $mock; $this->assertNull($cloned->cloned); } + public function testCreateStubSkipsConstructor(): void + { + $mock = $this->createStub(\Mockable::class); + + $this->assertNull($mock->constructorArgs); + } + + public function testCreateStubDisablesOriginalClone(): void + { + $mock = $this->createStub(\Mockable::class); + + $cloned = clone $mock; + $this->assertNull($cloned->cloned); + } + public function testConfiguredMockCanBeCreated(): void { /** @var \Mockable $mock */ @@ -924,6 +953,7 @@ public function testProvidingArrayThatMixesObjectsAndScalars(): void [123], ['foo'], [$this->createMock(\Mockable::class)], + [$this->createStub(\Mockable::class)], ]; $test = new \TestAutoreferenced('testJsonEncodeException', [$data]);