From 037d1471c7fc1a2cfa5775f68454aaa9501b62de Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Thu, 23 Feb 2023 08:39:54 +0100 Subject: [PATCH] Extract examples from Test Doubles chapter --- scripts/processed.json | 12 + .../test-doubles/AbstractClassTest.php | 16 + .../test-doubles/AbstractClassTest.php.out | 10 + .../test-doubles/AbstractTraitTest.php | 16 + .../test-doubles/AbstractTraitTest.php.out | 10 + src/examples/test-doubles/HelloService.wsdl | 52 ++ .../test-doubles/MockBuilderExampleTest.php | 24 + .../MockBuilderExampleTest.php.out | 18 + .../OnConsecutiveCallsExampleTest.php | 20 + .../OnConsecutiveCallsExampleTest.php.out | 18 + .../ReturnArgumentExampleTest.php | 21 + .../ReturnArgumentExampleTest.php.out | 18 + .../ReturnCallbackExampleTest.php | 18 + .../ReturnCallbackExampleTest.php.out | 18 + .../test-doubles/ReturnSelfExampleTest.php | 18 + .../ReturnSelfExampleTest.php.out | 18 + .../ReturnValueMapExampleTest.php | 26 + .../ReturnValueMapExampleTest.php.out | 18 + src/examples/test-doubles/SomeClassTest.php | 21 + .../test-doubles/SomeClassTest.php.out | 10 + src/examples/test-doubles/SubjectTest.php | 20 + src/examples/test-doubles/SubjectTest.php.out | 10 + .../ThrowExceptionExampleTest.php | 18 + .../ThrowExceptionExampleTest.php.out | 18 + .../test-doubles/WsdlStubExampleTest.php | 15 + .../test-doubles/WsdlStubExampleTest.php.out | 10 + .../test-doubles/src/AbstractClass.php | 10 + .../test-doubles/src/AbstractTrait.php | 11 + src/examples/test-doubles/src/C.php | 8 + src/examples/test-doubles/src/D.php | 4 + src/examples/test-doubles/src/Dependency.php | 5 + src/examples/test-doubles/src/Observer.php | 5 + src/examples/test-doubles/src/SomeClass.php | 12 + src/examples/test-doubles/src/Subject.php | 26 + src/examples/test-doubles/src/autoload.php | 9 + src/test-doubles.rst | 543 +++--------------- 36 files changed, 648 insertions(+), 458 deletions(-) create mode 100644 src/examples/test-doubles/AbstractClassTest.php create mode 100644 src/examples/test-doubles/AbstractClassTest.php.out create mode 100644 src/examples/test-doubles/AbstractTraitTest.php create mode 100644 src/examples/test-doubles/AbstractTraitTest.php.out create mode 100644 src/examples/test-doubles/HelloService.wsdl create mode 100644 src/examples/test-doubles/MockBuilderExampleTest.php create mode 100644 src/examples/test-doubles/MockBuilderExampleTest.php.out create mode 100644 src/examples/test-doubles/OnConsecutiveCallsExampleTest.php create mode 100644 src/examples/test-doubles/OnConsecutiveCallsExampleTest.php.out create mode 100644 src/examples/test-doubles/ReturnArgumentExampleTest.php create mode 100644 src/examples/test-doubles/ReturnArgumentExampleTest.php.out create mode 100644 src/examples/test-doubles/ReturnCallbackExampleTest.php create mode 100644 src/examples/test-doubles/ReturnCallbackExampleTest.php.out create mode 100644 src/examples/test-doubles/ReturnSelfExampleTest.php create mode 100644 src/examples/test-doubles/ReturnSelfExampleTest.php.out create mode 100644 src/examples/test-doubles/ReturnValueMapExampleTest.php create mode 100644 src/examples/test-doubles/ReturnValueMapExampleTest.php.out create mode 100644 src/examples/test-doubles/SomeClassTest.php create mode 100644 src/examples/test-doubles/SomeClassTest.php.out create mode 100644 src/examples/test-doubles/SubjectTest.php create mode 100644 src/examples/test-doubles/SubjectTest.php.out create mode 100644 src/examples/test-doubles/ThrowExceptionExampleTest.php create mode 100644 src/examples/test-doubles/ThrowExceptionExampleTest.php.out create mode 100644 src/examples/test-doubles/WsdlStubExampleTest.php create mode 100644 src/examples/test-doubles/WsdlStubExampleTest.php.out create mode 100644 src/examples/test-doubles/src/AbstractClass.php create mode 100644 src/examples/test-doubles/src/AbstractTrait.php create mode 100644 src/examples/test-doubles/src/C.php create mode 100644 src/examples/test-doubles/src/D.php create mode 100644 src/examples/test-doubles/src/Dependency.php create mode 100644 src/examples/test-doubles/src/Observer.php create mode 100644 src/examples/test-doubles/src/SomeClass.php create mode 100644 src/examples/test-doubles/src/Subject.php create mode 100644 src/examples/test-doubles/src/autoload.php diff --git a/scripts/processed.json b/scripts/processed.json index f0b4cf1b..22b6e5e2 100644 --- a/scripts/processed.json +++ b/scripts/processed.json @@ -64,6 +64,18 @@ "assertions\/XmlFileEqualsXmlFileTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fdd871bbdf213a7577d76f7fe09a64d129be693ba78a591d373e989201939e3a8", "assertions\/XmlStringEqualsXmlFileTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fa1304c8ff8bfbc552431b903d7f6f2e2cb1e5fbd8ad9ca56dd2eb692a1e30b82", "assertions\/XmlStringEqualsXmlStringTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3f1dd2147bce37b257a5c0ffbac15428c0452ff5186594f8e3a7050dac62c3ed0d", + "test-doubles\/AbstractClassTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3f4fd5eb08fc99ff72211555a2a600c06e24d2b9d84b7fd8a5f4dafd8226157de4", + "test-doubles\/AbstractTraitTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3f14043ded65431612d59342f82730fff8727112c1a961e9e8a41c9c2632ac9c9d", + "test-doubles\/MockBuilderExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fad2918a85c13ff5d2709e63e7bcadc4effced8350fcf67a7d317908d168a2976", + "test-doubles\/OnConsecutiveCallsExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3f1de253aa28ad75d1788f9c9f8708237941290d410c597847440e231f311c766f", + "test-doubles\/ReturnArgumentExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fe32f3bf754ab7633419ff0e92974c996ffcb3177bf3af95dc30e6875759c9e6f", + "test-doubles\/ReturnCallbackExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fbee0288e05e4a0286d8f679ce8beb931505e163dc66e4e436152599a0999ddac", + "test-doubles\/ReturnSelfExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3f879f246e98feb21bd344c74621323a67760a0e0ed3f33aec1573de5b811dea0b", + "test-doubles\/ReturnValueMapExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3ffeb7a733c93ca8c847fc0a95b85a94163a2a41ecd23dbd17d2f8bdbf146f0de3", + "test-doubles\/SomeClassTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fdf8031c9c1ad4106bfd497553351de434625fe6c7558b8873fb60006690001d9", + "test-doubles\/SubjectTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3ffc116a65ec6d3f66254ba4e004150b146881265dbdaa612103c74f1e0894d7d2", + "test-doubles\/ThrowExceptionExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fae60279c0e073dba3db8eb7750efbf2c22fe8d07c88db695edc4335381f4a1ea", + "test-doubles\/WsdlStubExampleTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3f1c6067971ffc807d088a0adeb94d513f2a93bce2bbb44312356c7cada6c3957a", "writing-tests-for-phpunit\/ArrayDiffTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3f63fa127c307a2782d6f5965b26c9c06a3d33e31ed47225e7a9a72aeea68a674f", "writing-tests-for-phpunit\/ArrayWeakComparisonTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3fdc95c700178a0d5324872f6ea646a7b53962f7e8b8027e5a550081ea1b9a6783", "writing-tests-for-phpunit\/DatabaseTest.php": "72d73f66a3eecf66f7121c1873a8307f3953c7717800d1885c306e9ec0a01b3ff0f34e406da5a40b7a46a2d369c440066b67af27665f9390fe831092942b1785", diff --git a/src/examples/test-doubles/AbstractClassTest.php b/src/examples/test-doubles/AbstractClassTest.php new file mode 100644 index 00000000..23b2ee9c --- /dev/null +++ b/src/examples/test-doubles/AbstractClassTest.php @@ -0,0 +1,16 @@ +getMockForAbstractClass(AbstractClass::class); + + $stub->expects($this->any()) + ->method('abstractMethod') + ->will($this->returnValue(true)); + + $this->assertTrue($stub->concreteMethod()); + } +} diff --git a/src/examples/test-doubles/AbstractClassTest.php.out b/src/examples/test-doubles/AbstractClassTest.php.out new file mode 100644 index 00000000..e0137296 --- /dev/null +++ b/src/examples/test-doubles/AbstractClassTest.php.out @@ -0,0 +1,10 @@ +./tools/phpunit tests/AbstractClassTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +. 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +OK (1 test, 1 assertion) diff --git a/src/examples/test-doubles/AbstractTraitTest.php b/src/examples/test-doubles/AbstractTraitTest.php new file mode 100644 index 00000000..ccfa7c4a --- /dev/null +++ b/src/examples/test-doubles/AbstractTraitTest.php @@ -0,0 +1,16 @@ +getMockForTrait(AbstractTrait::class); + + $mock->expects($this->any()) + ->method('abstractMethod') + ->will($this->returnValue(true)); + + $this->assertTrue($mock->concreteMethod()); + } +} diff --git a/src/examples/test-doubles/AbstractTraitTest.php.out b/src/examples/test-doubles/AbstractTraitTest.php.out new file mode 100644 index 00000000..64d6d0c7 --- /dev/null +++ b/src/examples/test-doubles/AbstractTraitTest.php.out @@ -0,0 +1,10 @@ +./tools/phpunit tests/AbstractTraitTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +. 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +OK (1 test, 1 assertion) diff --git a/src/examples/test-doubles/HelloService.wsdl b/src/examples/test-doubles/HelloService.wsdl new file mode 100644 index 00000000..cd883ec5 --- /dev/null +++ b/src/examples/test-doubles/HelloService.wsdl @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSDL File for HelloService + + + + + diff --git a/src/examples/test-doubles/MockBuilderExampleTest.php b/src/examples/test-doubles/MockBuilderExampleTest.php new file mode 100644 index 00000000..ee944fd5 --- /dev/null +++ b/src/examples/test-doubles/MockBuilderExampleTest.php @@ -0,0 +1,24 @@ +getMockBuilder(SomeClass::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->getMock(); + + // Configure the stub. + $stub->method('doSomething') + ->willReturn('foo'); + + // Calling $stub->doSomething() will now return + // 'foo'. + $this->assertSame('foo', $stub->doSomething()); + } +} diff --git a/src/examples/test-doubles/MockBuilderExampleTest.php.out b/src/examples/test-doubles/MockBuilderExampleTest.php.out new file mode 100644 index 00000000..0078c9b4 --- /dev/null +++ b/src/examples/test-doubles/MockBuilderExampleTest.php.out @@ -0,0 +1,18 @@ +./tools/phpunit tests/MockBuilderExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +E 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +There was 1 error: + +1) MockBuilderExampleTest::testStub +PHPUnit\Framework\MockObject\ClassIsFinalException: Class "SomeClass" is declared "final" and cannot be doubled + +/path/to/tests/MockBuilderExampleTest.php:14 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/src/examples/test-doubles/OnConsecutiveCallsExampleTest.php b/src/examples/test-doubles/OnConsecutiveCallsExampleTest.php new file mode 100644 index 00000000..3181bcab --- /dev/null +++ b/src/examples/test-doubles/OnConsecutiveCallsExampleTest.php @@ -0,0 +1,20 @@ +createStub(SomeClass::class); + + // Configure the stub. + $stub->method('doSomething') + ->will($this->onConsecutiveCalls(2, 3, 5, 7)); + + // $stub->doSomething() returns a different value each time + $this->assertSame(2, $stub->doSomething()); + $this->assertSame(3, $stub->doSomething()); + $this->assertSame(5, $stub->doSomething()); + } +} diff --git a/src/examples/test-doubles/OnConsecutiveCallsExampleTest.php.out b/src/examples/test-doubles/OnConsecutiveCallsExampleTest.php.out new file mode 100644 index 00000000..50b2c115 --- /dev/null +++ b/src/examples/test-doubles/OnConsecutiveCallsExampleTest.php.out @@ -0,0 +1,18 @@ +./tools/phpunit tests/OnConsecutiveCallsExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +E 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +There was 1 error: + +1) OnConsecutiveCallsExampleTest::testOnConsecutiveCallsStub +PHPUnit\Framework\MockObject\ClassIsFinalException: Class "SomeClass" is declared "final" and cannot be doubled + +/path/to/tests/OnConsecutiveCallsExampleTest.php:9 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/src/examples/test-doubles/ReturnArgumentExampleTest.php b/src/examples/test-doubles/ReturnArgumentExampleTest.php new file mode 100644 index 00000000..379dca98 --- /dev/null +++ b/src/examples/test-doubles/ReturnArgumentExampleTest.php @@ -0,0 +1,21 @@ +createStub(SomeClass::class); + + // Configure the stub. + $stub->method('doSomething') + ->will($this->returnArgument(0)); + + // $stub->doSomething('foo') returns 'foo' + $this->assertSame('foo', $stub->doSomething('foo')); + + // $stub->doSomething('bar') returns 'bar' + $this->assertSame('bar', $stub->doSomething('bar')); + } +} diff --git a/src/examples/test-doubles/ReturnArgumentExampleTest.php.out b/src/examples/test-doubles/ReturnArgumentExampleTest.php.out new file mode 100644 index 00000000..e07da325 --- /dev/null +++ b/src/examples/test-doubles/ReturnArgumentExampleTest.php.out @@ -0,0 +1,18 @@ +./tools/phpunit tests/ReturnArgumentExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +E 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +There was 1 error: + +1) ReturnArgumentExampleTest::testReturnArgumentStub +PHPUnit\Framework\MockObject\ClassIsFinalException: Class "SomeClass" is declared "final" and cannot be doubled + +/path/to/tests/ReturnArgumentExampleTest.php:9 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/src/examples/test-doubles/ReturnCallbackExampleTest.php b/src/examples/test-doubles/ReturnCallbackExampleTest.php new file mode 100644 index 00000000..3496cb88 --- /dev/null +++ b/src/examples/test-doubles/ReturnCallbackExampleTest.php @@ -0,0 +1,18 @@ +createStub(SomeClass::class); + + // Configure the stub. + $stub->method('doSomething') + ->will($this->returnCallback('str_rot13')); + + // $stub->doSomething($argument) returns str_rot13($argument) + $this->assertSame('fbzrguvat', $stub->doSomething('something')); + } +} diff --git a/src/examples/test-doubles/ReturnCallbackExampleTest.php.out b/src/examples/test-doubles/ReturnCallbackExampleTest.php.out new file mode 100644 index 00000000..8c542889 --- /dev/null +++ b/src/examples/test-doubles/ReturnCallbackExampleTest.php.out @@ -0,0 +1,18 @@ +./tools/phpunit tests/ReturnCallbackExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +E 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +There was 1 error: + +1) ReturnCallbackExampleTest::testReturnCallbackStub +PHPUnit\Framework\MockObject\ClassIsFinalException: Class "SomeClass" is declared "final" and cannot be doubled + +/path/to/tests/ReturnCallbackExampleTest.php:9 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/src/examples/test-doubles/ReturnSelfExampleTest.php b/src/examples/test-doubles/ReturnSelfExampleTest.php new file mode 100644 index 00000000..38d0e2ac --- /dev/null +++ b/src/examples/test-doubles/ReturnSelfExampleTest.php @@ -0,0 +1,18 @@ +createStub(SomeClass::class); + + // Configure the stub. + $stub->method('doSomething') + ->will($this->returnSelf()); + + // $stub->doSomething() returns $stub + $this->assertSame($stub, $stub->doSomething()); + } +} diff --git a/src/examples/test-doubles/ReturnSelfExampleTest.php.out b/src/examples/test-doubles/ReturnSelfExampleTest.php.out new file mode 100644 index 00000000..274220b1 --- /dev/null +++ b/src/examples/test-doubles/ReturnSelfExampleTest.php.out @@ -0,0 +1,18 @@ +./tools/phpunit tests/ReturnSelfExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +E 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +There was 1 error: + +1) ReturnSelfExampleTest::testReturnSelf +PHPUnit\Framework\MockObject\ClassIsFinalException: Class "SomeClass" is declared "final" and cannot be doubled + +/path/to/tests/ReturnSelfExampleTest.php:9 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/src/examples/test-doubles/ReturnValueMapExampleTest.php b/src/examples/test-doubles/ReturnValueMapExampleTest.php new file mode 100644 index 00000000..4c22a910 --- /dev/null +++ b/src/examples/test-doubles/ReturnValueMapExampleTest.php @@ -0,0 +1,26 @@ +createStub(SomeClass::class); + + // Create a map of arguments to return values. + $map = [ + ['a', 'b', 'c', 'd'], + ['e', 'f', 'g', 'h'], + ]; + + // Configure the stub. + $stub->method('doSomething') + ->will($this->returnValueMap($map)); + + // $stub->doSomething() returns different values depending on + // the provided arguments. + $this->assertSame('d', $stub->doSomething('a', 'b', 'c')); + $this->assertSame('h', $stub->doSomething('e', 'f', 'g')); + } +} diff --git a/src/examples/test-doubles/ReturnValueMapExampleTest.php.out b/src/examples/test-doubles/ReturnValueMapExampleTest.php.out new file mode 100644 index 00000000..fa582876 --- /dev/null +++ b/src/examples/test-doubles/ReturnValueMapExampleTest.php.out @@ -0,0 +1,18 @@ +./tools/phpunit tests/ReturnValueMapExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +E 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +There was 1 error: + +1) ReturnValueMapExampleTest::testReturnValueMapStub +PHPUnit\Framework\MockObject\ClassIsFinalException: Class "SomeClass" is declared "final" and cannot be doubled + +/path/to/tests/ReturnValueMapExampleTest.php:9 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/src/examples/test-doubles/SomeClassTest.php b/src/examples/test-doubles/SomeClassTest.php new file mode 100644 index 00000000..002f42ba --- /dev/null +++ b/src/examples/test-doubles/SomeClassTest.php @@ -0,0 +1,21 @@ +createStub(Dependency::class); + + // Configure the test stub + $dependency->method('doSomething') + ->willReturn('foo'); + + $result = $sut->doSomething($dependency); + + $this->assertStringEndsWith('foo', $result); + } +} diff --git a/src/examples/test-doubles/SomeClassTest.php.out b/src/examples/test-doubles/SomeClassTest.php.out new file mode 100644 index 00000000..f41307c5 --- /dev/null +++ b/src/examples/test-doubles/SomeClassTest.php.out @@ -0,0 +1,10 @@ +./tools/phpunit tests/SomeClassTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +. 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +OK (1 test, 1 assertion) diff --git a/src/examples/test-doubles/SubjectTest.php b/src/examples/test-doubles/SubjectTest.php new file mode 100644 index 00000000..d0bd8258 --- /dev/null +++ b/src/examples/test-doubles/SubjectTest.php @@ -0,0 +1,20 @@ +createMock(Observer::class); + + $observer->expects($this->once()) + ->method('update') + ->with($this->identicalTo('something')); + + $subject = new Subject; + + $subject->attach($observer); + + $subject->doSomething(); + } +} diff --git a/src/examples/test-doubles/SubjectTest.php.out b/src/examples/test-doubles/SubjectTest.php.out new file mode 100644 index 00000000..238d17d6 --- /dev/null +++ b/src/examples/test-doubles/SubjectTest.php.out @@ -0,0 +1,10 @@ +./tools/phpunit tests/SubjectTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +. 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +OK (1 test, 1 assertion) diff --git a/src/examples/test-doubles/ThrowExceptionExampleTest.php b/src/examples/test-doubles/ThrowExceptionExampleTest.php new file mode 100644 index 00000000..b5efc563 --- /dev/null +++ b/src/examples/test-doubles/ThrowExceptionExampleTest.php @@ -0,0 +1,18 @@ +createStub(SomeClass::class); + + // Configure the stub. + $stub->method('doSomething') + ->will($this->throwException(new Exception)); + + // $stub->doSomething() throws Exception + $stub->doSomething(); + } +} diff --git a/src/examples/test-doubles/ThrowExceptionExampleTest.php.out b/src/examples/test-doubles/ThrowExceptionExampleTest.php.out new file mode 100644 index 00000000..5a5a4207 --- /dev/null +++ b/src/examples/test-doubles/ThrowExceptionExampleTest.php.out @@ -0,0 +1,18 @@ +./tools/phpunit tests/ThrowExceptionExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +E 1 / 1 (100%) + +Time: 00:00.001, Memory: 14.29 MB + +There was 1 error: + +1) ThrowExceptionExampleTest::testThrowExceptionStub +PHPUnit\Framework\MockObject\ClassIsFinalException: Class "SomeClass" is declared "final" and cannot be doubled + +/path/to/tests/ThrowExceptionExampleTest.php:9 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/src/examples/test-doubles/WsdlStubExampleTest.php b/src/examples/test-doubles/WsdlStubExampleTest.php new file mode 100644 index 00000000..0e5ddc90 --- /dev/null +++ b/src/examples/test-doubles/WsdlStubExampleTest.php @@ -0,0 +1,15 @@ +getMockFromWsdl(__DIR__ . '/HelloService.wsdl'); + + $service->method('sayHello') + ->willReturn('Hello'); + + $this->assertSame('Hello', $service->sayHello('message')); + } +} diff --git a/src/examples/test-doubles/WsdlStubExampleTest.php.out b/src/examples/test-doubles/WsdlStubExampleTest.php.out new file mode 100644 index 00000000..765882db --- /dev/null +++ b/src/examples/test-doubles/WsdlStubExampleTest.php.out @@ -0,0 +1,10 @@ +./tools/phpunit tests/WsdlStubExampleTest.php +PHPUnit 10.0.11 by Sebastian Bergmann and contributors. + +Runtime: PHP 8.2.3 + +. 1 / 1 (100%) + +Time: 00:00.004, Memory: 14.29 MB + +OK (1 test, 1 assertion) diff --git a/src/examples/test-doubles/src/AbstractClass.php b/src/examples/test-doubles/src/AbstractClass.php new file mode 100644 index 00000000..8629d27d --- /dev/null +++ b/src/examples/test-doubles/src/AbstractClass.php @@ -0,0 +1,10 @@ +abstractMethod(); + } + + abstract public function abstractMethod(); +} diff --git a/src/examples/test-doubles/src/AbstractTrait.php b/src/examples/test-doubles/src/AbstractTrait.php new file mode 100644 index 00000000..c1cbc4a2 --- /dev/null +++ b/src/examples/test-doubles/src/AbstractTrait.php @@ -0,0 +1,11 @@ +abstractMethod(); + } + + abstract public function abstractMethod(); +} diff --git a/src/examples/test-doubles/src/C.php b/src/examples/test-doubles/src/C.php new file mode 100644 index 00000000..487aa96d --- /dev/null +++ b/src/examples/test-doubles/src/C.php @@ -0,0 +1,8 @@ +doSomething(); + } +} diff --git a/src/examples/test-doubles/src/Subject.php b/src/examples/test-doubles/src/Subject.php new file mode 100644 index 00000000..4fdf2502 --- /dev/null +++ b/src/examples/test-doubles/src/Subject.php @@ -0,0 +1,26 @@ +observers[] = $observer; + } + + public function doSomething(): void + { + // ... + + $this->notify('something'); + } + + private function notify(string $argument): void + { + foreach ($this->observers as $observer) { + $observer->update($argument); + } + } + + // ... +} diff --git a/src/examples/test-doubles/src/autoload.php b/src/examples/test-doubles/src/autoload.php new file mode 100644 index 00000000..bac1e0d2 --- /dev/null +++ b/src/examples/test-doubles/src/autoload.php @@ -0,0 +1,9 @@ +`_ that PHPUnit provides to specify the behavior for the stub. In essence, this means that @@ -87,59 +87,18 @@ you do not need to create several temporary objects and wire them together after Instead, you chain method calls as shown in the example. This leads to more readable and "fluent" code. -.. code-block:: php - :caption: The class we want to test - :name: test-doubles.test-stubs.examples.SomeClass.php +.. literalinclude:: examples/test-doubles/src/SomeClass.php + :caption: The class we want to test + :language: php - doSomething(); - } - } - - -.. code-block:: php - :caption: The dependency we want to stub - :name: test-doubles.test-stubs.examples.Dependency.php - - createStub(Dependency::class); - - // Configure the test stub - $dependency->method('doSomething') - ->willReturn('foo'); - - $result = $sut->doSomething($dependency); - - $this->assertStringEndsWith('foo', $result); - } - } +.. literalinclude:: examples/test-doubles/SomeClassTest.php + :caption: Stubbing a method call to return a fixed value + :name: test-doubles.test-stubs.examples.SomeClassTest.php + :language: php .. admonition:: Limitation: Methods named "method" @@ -156,18 +115,9 @@ the desired behavior when the ``createStub()`` method is used. Please note that ``createStub()`` will automatically and recursively stub return values based on a method's return type. Consider the example shown below: -.. code-block:: php - :caption: A method with a return type declaration - :name: test-doubles.test-stubs.examples.returnTypeDeclaration.php - - getMockBuilder(SomeClass::class) - ->disableOriginalConstructor() - ->disableOriginalClone() - ->disableArgumentCloning() - ->disallowMockingUnknownTypes() - ->getMock(); - - // Configure the stub. - $stub->method('doSomething') - ->willReturn('foo'); - - // Calling $stub->doSomething() will now return - // 'foo'. - $this->assertSame('foo', $stub->doSomething()); - } - } +Here is an example that shows how to use the Mock Builder's fluent interface to configure +the creation of the test double. The configuration of this test double uses the same best +practice defaults used by ``createStub()``: + +.. literalinclude:: examples/test-doubles/MockBuilderExampleTest.php + :caption: Using the Mock Builder API to configure how the test double class is generated + :language: php In the examples so far we have been returning simple values using ``willReturn($value)``. This is a shorthand syntax provided for convenience. :numref:`test-doubles.test-stubs.shorthands` @@ -242,181 +166,51 @@ shows the available stubbing shorthands alongside their longer counterparts. We can use variations on this longer syntax to achieve more complex stubbing behaviour. Sometimes you want to return one of the arguments of a method call (unchanged) as the -result of a stubbed method call. :numref:`test-doubles.test-stubs.examples.StubTest3.php` -shows how you can achieve this using ``returnArgument()`` instead of ``returnValue()``. - -.. code-block:: php - :caption: Stubbing a method call to return one of the arguments - :name: test-doubles.test-stubs.examples.StubTest3.php - - createStub(SomeClass::class); - - // Configure the stub. - $stub->method('doSomething') - ->will($this->returnArgument(0)); - - // $stub->doSomething('foo') returns 'foo' - $this->assertSame('foo', $stub->doSomething('foo')); - - // $stub->doSomething('bar') returns 'bar' - $this->assertSame('bar', $stub->doSomething('bar')); - } - } +.. literalinclude:: examples/test-doubles/ReturnArgumentExampleTest.php + :caption: Using returnArgument() to stub a method call to return one of the arguments + :language: php When testing a fluent interface, it is sometimes useful to have a stubbed method return -a reference to the stubbed object. :numref:`test-doubles.test-stubs.examples.StubTest4.php` -shows how you can use ``returnSelf()`` to achieve this. - -.. code-block:: php - :caption: Stubbing a method call to return a reference to the stub object - :name: test-doubles.test-stubs.examples.StubTest4.php - - createStub(SomeClass::class); - - // Configure the stub. - $stub->method('doSomething') - ->will($this->returnSelf()); +a reference to the stubbed object. Here is an example that shows how you can use +``returnSelf()`` to achieve this: - // $stub->doSomething() returns $stub - $this->assertSame($stub, $stub->doSomething()); - } - } +.. literalinclude:: examples/test-doubles/ReturnSelfExampleTest.php + :caption: Using returnSelf() to stub a method call to return a reference to the stub object + :language: php Sometimes a stubbed method should return different values depending on a predefined list -of arguments. You can use ``returnValueMap()`` to create a map that associates arguments -with corresponding return values. See :numref:`test-doubles.test-stubs.examples.StubTest5.php` -for an example. - -.. code-block:: php - :caption: Stubbing a method call to return the value from a map - :name: test-doubles.test-stubs.examples.StubTest5.php - - createStub(SomeClass::class); - - // Create a map of arguments to return values. - $map = [ - ['a', 'b', 'c', 'd'], - ['e', 'f', 'g', 'h'] - ]; - - // Configure the stub. - $stub->method('doSomething') - ->will($this->returnValueMap($map)); - - // $stub->doSomething() returns different values depending on - // the provided arguments. - $this->assertSame('d', $stub->doSomething('a', 'b', 'c')); - $this->assertSame('h', $stub->doSomething('e', 'f', 'g')); - } - } +of arguments. Here is an example that shows how to use ``returnValueMap()`` to create a map +that associates arguments with corresponding return values: + +.. literalinclude:: examples/test-doubles/ReturnValueMapExampleTest.php + :caption: Using returnValueMap() to stub a method call to return the value from a map + :language: php When the stubbed method call should return a calculated value instead of a fixed one (see ``returnValue()``) or an (unchanged) argument (see ``returnArgument()``), you can use ``returnCallback()`` to have the stubbed method return the result of a callback -function or method. See :numref:`test-doubles.test-stubs.examples.StubTest6.php` for an example. - -.. code-block:: php - :caption: Stubbing a method call to return a value from a callback - :name: test-doubles.test-stubs.examples.StubTest6.php - - createStub(SomeClass::class); +function or method. Here is an example: - // Configure the stub. - $stub->method('doSomething') - ->will($this->returnCallback('str_rot13')); - - // $stub->doSomething($argument) returns str_rot13($argument) - $this->assertSame('fbzrguvat', $stub->doSomething('something')); - } - } +.. literalinclude:: examples/test-doubles/ReturnCallbackExampleTest.php + :caption: Using returnCallback() to stub a method call to return a value from a callback + :language: php A simpler alternative to setting up a callback method may be to specify a list of desired -return values. You can do this with the ``onConsecutiveCalls()`` method. See -:numref:`test-doubles.test-stubs.examples.StubTest7.php` for an example. - -.. code-block:: php - :caption: Stubbing a method call to return a list of values in the specified order - :name: test-doubles.test-stubs.examples.StubTest7.php - - createStub(SomeClass::class); - - // Configure the stub. - $stub->method('doSomething') - ->will($this->onConsecutiveCalls(2, 3, 5, 7)); - - // $stub->doSomething() returns a different value each time - $this->assertSame(2, $stub->doSomething()); - $this->assertSame(3, $stub->doSomething()); - $this->assertSame(5, $stub->doSomething()); - } - } - -Instead of returning a value, a stubbed method can also raise an exception. -:numref:`test-doubles.test-stubs.examples.StubTest8.php` shows how to use -``throwException()`` to do this. +return values. You can do this with the ``onConsecutiveCalls()`` method. Here is an example: -.. code-block:: php - :caption: Stubbing a method call to throw an exception - :name: test-doubles.test-stubs.examples.StubTest8.php +.. literalinclude:: examples/test-doubles/OnConsecutiveCallsExampleTest.php + :caption: Using onConsecutiveCalls() to stub a method call to return a list of values in the specified order + :language: php - createStub(SomeClass::class); - - // Configure the stub. - $stub->method('doSomething') - ->will($this->throwException(new Exception)); +Instead of returning a value, a stubbed method can also raise an exception. +Here is an example that shows how to use ``throwException()`` to do this: - // $stub->doSomething() throws Exception - $stub->doSomething(); - } - } +.. literalinclude:: examples/test-doubles/ThrowExceptionExampleTest.php + :caption: Using throwException() to stub a method call to throw an exception + :language: php Alternatively, you can write the stub yourself and improve your design along the way. Widely used resources are accessed through a single facade, @@ -455,51 +249,23 @@ just a test stub plus assertions; it is used in a fundamentally different way" Here is an example: suppose we want to test that the correct method, ``update()`` in our example, is called on an object that observes another object. -:numref:`test-doubles.mock-objects.examples.SUT.php` shows the code for the -``Subject`` class and the ``Observer`` interface that are part of the System -under Test (SUT). - -.. code-block:: php - :caption: Subject class and Observer interface that are part of the System under Test (SUT) - :name: test-doubles.mock-objects.examples.SUT.php - - observers[] = $observer; - } - - public function doSomething() - { - // ... +Here is the code for the ``Subject`` class and the ``Observer`` interface that are part +of the System under Test (SUT): - $this->notify('something'); - } +.. literalinclude:: examples/test-doubles/src/Subject.php + :caption: Subject class that is part of the System under Test (SUT) + :language: php - private function notify(string $argument): void - { - foreach ($this->observers as $observer) { - $observer->update($argument); - } - } +.. literalinclude:: examples/test-doubles/src/Observer.php + :caption: Observer interface that is part of the System under Test (SUT) + :language: php - // ... - } +Here is an example that shows how to use a mock object to test the interaction between +``Subject`` and ``Observer`` objects: - interface Observer - { - public function update(string $argument): void; - } - -:numref:`test-doubles.mock-objects.examples.SubjectTest.php` -shows how to use a mock object to test the interaction between -``Subject`` and ``Observer`` objects. +.. literalinclude:: examples/test-doubles/SubjectTest.php + :caption: Testing that a method gets called once and with a specified argument + :language: php We first use the ``createMock()`` method that is provided by the ``PHPUnit\Framework\TestCase`` class to create a mock object for the ``Observer``. @@ -508,31 +274,6 @@ Because we are interested in verifying that a method is called, and which arguments it is called with, we introduce the ``expects()`` and ``with()`` methods to specify how this interaction should look. -.. code-block:: php - :caption: Testing that a method gets called once and with a specified argument - :name: test-doubles.mock-objects.examples.SubjectTest.php - - createMock(Observer::class); - - $observer->expects($this->once()) - ->method('update') - ->with($this->identicalTo('something')); - - $subject = new Subject; - - $subject->attach($observer); - - $subject->doSomething(); - } - } - The ``with()`` method can take any number of arguments, corresponding to the number of arguments to the method being mocked. You can specify more advanced constraints on the method's arguments than a simple match. @@ -652,72 +393,26 @@ The ``getMockForTrait()`` method returns a mock object that uses a specified trait. All abstract methods of the given trait are mocked. This allows for testing the concrete methods of a trait. -.. code-block:: php - :caption: Testing the concrete methods of a trait - :name: test-doubles.mock-objects.examples.TraitClassTest.php - - abstractMethod(); - } - - public abstract function abstractMethod(); - } +.. literalinclude:: examples/test-doubles/src/AbstractTrait.php + :caption: A trait with an abstract method + :language: php - final class TraitClassTest extends TestCase - { - public function testConcreteMethod(): void - { - $mock = $this->getMockForTrait(AbstractTrait::class); - - $mock->expects($this->any()) - ->method('abstractMethod') - ->will($this->returnValue(true)); - - $this->assertTrue($mock->concreteMethod()); - } - } +.. literalinclude:: examples/test-doubles/AbstractTraitTest.php + :caption: A test for a concrete method of a trait + :language: php The ``getMockForAbstractClass()`` method returns a mock object for an abstract class. All abstract methods of the given abstract class are mocked. This allows for testing the concrete methods of an abstract class. -.. code-block:: php - :caption: Testing the concrete methods of an abstract class - :name: test-doubles.mock-objects.examples.AbstractClassTest.php - - abstractMethod(); - } - - public abstract function abstractMethod(); - } - - final class AbstractClassTest extends TestCase - { - public function testConcreteMethod(): void - { - $stub = $this->getMockForAbstractClass(AbstractClass::class); - - $stub->expects($this->any()) - ->method('abstractMethod') - ->will($this->returnValue(true)); - - $this->assertTrue($stub->concreteMethod()); - } - } +.. literalinclude:: examples/test-doubles/AbstractClassTest.php + :caption: A test for a concrete method of an abstract class + :language: php .. _test-doubles.stubbing-and-mocking-web-services: @@ -726,81 +421,13 @@ Stubbing and Mocking Web Services When your application interacts with a web service you want to test it without actually interacting with the web service. To create stubs -and mocks of web services, the ``getMockFromWsdl()`` -can be used like ``getMock()`` (see above). The only -difference is that ``getMockFromWsdl()`` returns a stub or -mock based on a web service description in WSDL and ``getMock()`` -returns a stub or mock based on a PHP class or interface. - -:numref:`test-doubles.stubbing-and-mocking-web-services.examples.GoogleTest.php` -shows how ``getMockFromWsdl()`` can be used to stub, for -example, the web service described in :file:`GoogleSearch.wsdl`. - -.. code-block:: php - :caption: Stubbing a web service - :name: test-doubles.stubbing-and-mocking-web-services.examples.GoogleTest.php - - getMockFromWsdl( - 'GoogleSearch.wsdl', 'GoogleSearch' - ); - - $directoryCategory = new stdClass; - $directoryCategory->fullViewableName = ''; - $directoryCategory->specialEncoding = ''; - - $element = new stdClass; - $element->summary = ''; - $element->URL = 'https://phpunit.de/'; - $element->snippet = '...'; - $element->title = 'PHPUnit'; - $element->cachedSize = '11k'; - $element->relatedInformationPresent = true; - $element->hostName = 'phpunit.de'; - $element->directoryCategory = $directoryCategory; - $element->directoryTitle = ''; - - $result = new stdClass; - $result->documentFiltering = false; - $result->searchComments = ''; - $result->estimatedTotalResultsCount = 3.9000; - $result->estimateIsExact = false; - $result->resultElements = [$element]; - $result->searchQuery = 'PHPUnit'; - $result->startIndex = 1; - $result->endIndex = 1; - $result->searchTips = ''; - $result->directoryCategories = []; - $result->searchTime = 0.248822; - - $googleSearch->expects($this->any()) - ->method('doGoogleSearch') - ->will($this->returnValue($result)); - - /** - * $googleSearch->doGoogleSearch() will now return a stubbed result and - * the web service's doGoogleSearch() method will not be invoked. - */ - $this->assertEquals( - $result, - $googleSearch->doGoogleSearch( - '00000000000000000000000000000000', - 'PHPUnit', - 0, - 1, - false, - '', - false, - '', - '', - '' - ) - ); - } - } +and mocks of web services, the ``getMockFromWsdl()`` method can be used. + +This method returns a test stub based on a web service description in WSDL whereas +``createStub()``, for instance, returns a test stub based on an interface or on a class. + +Here is an example that shows how to stub the web service described in :file:`HelloService.wsdl`: + +.. literalinclude:: examples/test-doubles/WsdlStubExampleTest.php + :caption: Stubbing a web service + :language: php