From c9f723530d2ad0d3407eff2d67853f8eb5c6deda Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Sat, 10 Apr 2021 21:11:57 +0100 Subject: [PATCH 1/4] feat(mock): adds work in progress --- src/Exceptions/MissingDependency.php | 24 ++++++++++ src/Functions.php | 13 ++++++ src/Mock.php | 69 ++++++++++++++++++++++++++++ tests/.snapshots/success.txt | 8 +++- tests/Features/Helpers.php | 2 + tests/Features/Mocks.php | 27 +++++++---- tests/Helpers.php | 9 +--- 7 files changed, 134 insertions(+), 18 deletions(-) create mode 100644 src/Exceptions/MissingDependency.php create mode 100644 src/Mock.php diff --git a/src/Exceptions/MissingDependency.php b/src/Exceptions/MissingDependency.php new file mode 100644 index 00000000..e7d7940d --- /dev/null +++ b/src/Exceptions/MissingDependency.php @@ -0,0 +1,24 @@ +afterAll->set($closure); } + +if (!function_exists('mock')) { + /** + * Creates a new mock with the given class or object. + * + * @param string|object $object + */ + function mock($object): Mock + { + return new Mock($object); + } +} diff --git a/src/Mock.php b/src/Mock.php new file mode 100644 index 00000000..31d35fdb --- /dev/null +++ b/src/Mock.php @@ -0,0 +1,69 @@ +mock = Mockery::mock($object); + } + + /** + * Define mock expectations. + * + * @param mixed ...$methods + * + * @return \Mockery\MockInterface|\Mockery\LegacyMockInterface + */ + public function expect(...$methods) + { + foreach ($methods as $method => $result) { + /* @phpstan-ignore-next-line */ + $this->mock + ->shouldReceive((string) $method) + ->andReturn($result); + } + + return $this->mock; + } + + /** + * Proxies calls to the original mock object. + * + * @param array $arguments + * + * @return mixed + */ + public function __call(string $method, array $arguments) + { + /* @phpstan-ignore-next-line */ + return $this->mock->{$method}($arguments); + } +} diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 625557a8..8fa58f1a 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -63,6 +63,7 @@ ✓ it allows to call underlying protected/private methods ✓ it throws error if method do not exist ✓ it can forward unexpected calls to any global function + ✓ it can use helpers from helpers file PASS Tests\Features\HigherOrderTests ✓ it proxies calls to object @@ -77,7 +78,8 @@ ✓ it will throw exception from call if no macro exists PASS Tests\Features\Mocks - ✓ it has bar + ✓ it can mock methods + ✓ access to the mock object PASS Tests\Features\PendingHigherOrderTests ✓ get 'foo' → get 'bar' → expect true → toBeTrue @@ -221,5 +223,9 @@ ✓ it is a test ✓ it uses correct parent class +<<<<<<< HEAD Tests: 7 skipped, 119 passed +======= + Tests: 7 skipped, 117 passed +>>>>>>> feat(mock): adds work in progress \ No newline at end of file diff --git a/tests/Features/Helpers.php b/tests/Features/Helpers.php index 3203da9b..0f399fa4 100644 --- a/tests/Features/Helpers.php +++ b/tests/Features/Helpers.php @@ -42,3 +42,5 @@ it('throws error if method do not exist', function () { })->throws(\ReflectionException::class, 'Call to undefined method PHPUnit\Framework\TestCase::name()'); it('can forward unexpected calls to any global function')->_assertThat(); + +it('can use helpers from helpers file')->myAssertTrue(true); diff --git a/tests/Features/Mocks.php b/tests/Features/Mocks.php index 41268524..51b896d5 100644 --- a/tests/Features/Mocks.php +++ b/tests/Features/Mocks.php @@ -1,17 +1,24 @@ shouldReceive('bar') - ->times(1) - ->andReturn(2); +it('can mock methods', function () { + $mock = mock(Http::class)->expect( + get: 'foo', + ); - $mock->bar(); -}); + expect($mock->get())->toBe('foo'); +})->skip(((float) phpversion()) < 8.0); + +test('access to the mock object', function () { + $mock = mock(Http::class); + expect($mock->expect())->toBeInstanceOf(MockInterface::class); + + expect($mock->shouldReceive())->toBeInstanceOf(CompositeExpectation::class); +})->skip(((float) phpversion()) < 8.0); diff --git a/tests/Helpers.php b/tests/Helpers.php index ee869257..57d38e06 100644 --- a/tests/Helpers.php +++ b/tests/Helpers.php @@ -1,11 +1,6 @@ assertTrue($value); } From 99d6fb9f5fdab515fb0387b9524a254bfb586a0d Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Fri, 14 May 2021 23:59:50 +0100 Subject: [PATCH 2/4] feat(mock): updates tests --- tests/.snapshots/success.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 8fa58f1a..58d5baf5 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -223,9 +223,5 @@ ✓ it is a test ✓ it uses correct parent class -<<<<<<< HEAD - Tests: 7 skipped, 119 passed -======= - Tests: 7 skipped, 117 passed ->>>>>>> feat(mock): adds work in progress + Tests: 7 skipped, 121 passed \ No newline at end of file From 7023cec43251dce26f41d18b93b616ffe6649679 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Sat, 15 May 2021 01:01:46 +0100 Subject: [PATCH 3/4] feat(mock): updates tests --- src/Mock.php | 13 ++++++++++--- tests/.snapshots/success.txt | 2 +- tests/Features/Mocks.php | 6 +++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Mock.php b/src/Mock.php index 31d35fdb..12dfed94 100644 --- a/src/Mock.php +++ b/src/Mock.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Pest; +use InvalidArgumentException; use Mockery; use Pest\Exceptions\MissingDependency; @@ -44,11 +45,17 @@ final class Mock */ public function expect(...$methods) { - foreach ($methods as $method => $result) { + foreach ($methods as $method => $expectation) { /* @phpstan-ignore-next-line */ - $this->mock + $method = $this->mock ->shouldReceive((string) $method) - ->andReturn($result); + ->once(); + + if (!is_callable($expectation)) { + throw new InvalidArgumentException(sprintf('Method %s from %s expects a callable as expectation.', $method, $method->mock()->mockery_getName(), )); + } + + $method->andReturnUsing($expectation); } return $this->mock; diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 58d5baf5..b471823f 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -79,7 +79,7 @@ PASS Tests\Features\Mocks ✓ it can mock methods - ✓ access to the mock object + ✓ it allows access to the underlying mockery mock PASS Tests\Features\PendingHigherOrderTests ✓ get 'foo' → get 'bar' → expect true → toBeTrue diff --git a/tests/Features/Mocks.php b/tests/Features/Mocks.php index 51b896d5..ac2bb545 100644 --- a/tests/Features/Mocks.php +++ b/tests/Features/Mocks.php @@ -10,15 +10,15 @@ interface Http it('can mock methods', function () { $mock = mock(Http::class)->expect( - get: 'foo', + get: fn () => 'foo', ); expect($mock->get())->toBe('foo'); })->skip(((float) phpversion()) < 8.0); -test('access to the mock object', function () { +it('allows access to the underlying mockery mock', function () { $mock = mock(Http::class); - expect($mock->expect())->toBeInstanceOf(MockInterface::class); + expect($mock->expect())->toBeInstanceOf(MockInterface::class); expect($mock->shouldReceive())->toBeInstanceOf(CompositeExpectation::class); })->skip(((float) phpversion()) < 8.0); From 88dc74bbe47f556e97becfdd04150514fde774c0 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Sat, 15 May 2021 01:02:58 +0100 Subject: [PATCH 4/4] feat(mock): updates tests --- tests/Features/Mocks.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Features/Mocks.php b/tests/Features/Mocks.php index ac2bb545..7d1b213f 100644 --- a/tests/Features/Mocks.php +++ b/tests/Features/Mocks.php @@ -16,6 +16,14 @@ it('can mock methods', function () { expect($mock->get())->toBe('foo'); })->skip(((float) phpversion()) < 8.0); +it('can access to arguments', function () { + $mock = mock(Http::class)->expect( + get: fn ($foo) => $foo, + ); + + expect($mock->get('foo'))->toBe('foo'); +})->skip(((float) phpversion()) < 8.0); + it('allows access to the underlying mockery mock', function () { $mock = mock(Http::class);