Skip to content

Commit

Permalink
Drop Prophecy in favor of PHPUnit's mocking
Browse files Browse the repository at this point in the history
  • Loading branch information
rybakit committed Apr 7, 2020
1 parent d17b079 commit f9bdc0c
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 29 deletions.
12 changes: 12 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,16 @@
<directory name="vendor" />
</ignoreFiles>
</projectFiles>

<issueHandlers>
<InternalMethod>
<errorLevel type="suppress">
<referencedMethod name="PHPUnit\Framework\MockObject\Builder\InvocationMocker::method" />
<referencedMethod name="PHPUnit\Framework\MockObject\Builder\InvocationMocker::with" />
<referencedMethod name="PHPUnit\Framework\MockObject\Builder\InvocationMocker::willReturn" />
<referencedMethod name="PHPUnit\Framework\MockObject\Builder\InvocationMocker::willReturnOnConsecutiveCalls" />
<referencedMethod name="PHPUnit\Framework\TestCase::__construct" />
</errorLevel>
</InternalMethod>
</issueHandlers>
</psalm>
5 changes: 1 addition & 4 deletions src/Client/ClientMocking.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,17 @@

namespace Tarantool\PhpUnit\Client;

use Prophecy\Prophecy\ObjectProphecy;
use Tarantool\Client\Client;

trait ClientMocking
{
protected function getMockClientBuilder() : MockClientBuilder
{
return new MockClientBuilder(\Closure::fromCallable([$this, 'prophesize']));
return new MockClientBuilder($this);
}

protected function createMockClient() : Client
{
return $this->getMockClientBuilder()->build();
}

abstract protected function prophesize(?string $classOrInterface = null) : ObjectProphecy;
}
44 changes: 44 additions & 0 deletions src/Client/IsRequestType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/**
* This file is part of the tarantool/phpunit-extras package.
*
* (c) Eugene Leonovich <gen.work@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Tarantool\PhpUnit\Client;

use PHPUnit\Framework\Constraint\Constraint;
use Tarantool\Client\Request\Request;
use Tarantool\Client\RequestTypes;

final class IsRequestType extends Constraint
{
/** @var int */
private $requestType;

public function __construct(int $requestType)
{
// needed for backward compatibility with PHPUnit 7
if (\is_callable('parent::__construct')) {
parent::__construct();
}

$this->requestType = $requestType;
}

public function toString() : string
{
return sprintf('is a "%s" request', strtoupper(RequestTypes::getName($this->requestType)));
}

protected function matches($other) : bool
{
return $other instanceof Request && $other->getType() === $this->requestType;
}
}
61 changes: 38 additions & 23 deletions src/Client/MockClientBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@

namespace Tarantool\PhpUnit\Client;

use Prophecy\Argument;
use Prophecy\Argument\Token\TokenInterface;
use Prophecy\Prophecy\ObjectProphecy;
use Prophecy\Prophet;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Tarantool\Client\Client;
use Tarantool\Client\Connection\Connection;
use Tarantool\Client\Handler\Handler;
Expand All @@ -26,8 +25,8 @@

final class MockClientBuilder
{
/** @var \Closure */
private $prophesize;
/** @var TestCase */
private $testCase;

/** @var \SplObjectStorage<object, array<int, Response>> */
private $requests;
Expand All @@ -38,21 +37,23 @@ final class MockClientBuilder
/** @var Packer|null */
private $packer;

public function __construct(\Closure $prophesize)
public function __construct(TestCase $testCase)
{
$this->prophesize = $prophesize;
$this->testCase = $testCase;
$this->requests = new \SplObjectStorage();
}

public static function buildDefault() : Client
{
$self = new self(\Closure::fromCallable([new Prophet(), 'prophesize']));
/** @psalm-suppress PropertyNotSetInConstructor */
$self = new self(new class() extends TestCase {
});

return $self->build();
}

/**
* @param Request|TokenInterface $request
* @param Request|Constraint $request
* @param Response ...$responses
*/
public function shouldHandle($request, ...$responses) : self
Expand All @@ -79,63 +80,77 @@ public function willUsePacker(Packer $packer) : self
public function build() : Client
{
/** @var Handler $handler */
$handler = $this->createHandler()->reveal();
$handler = $this->createHandler();

return new Client($handler);
}

private function createHandler() : ObjectProphecy
private function createHandler() : MockObject
{
$handler = ($this->prophesize)(Handler::class);
$handler = $this->createMock(Handler::class);

$connection = $this->createConnection();
$handler->getConnection()->willReturn($connection);
$handler->method('getConnection')->willReturn($connection);

$packer = $this->createPacker();
$handler->getPacker()->willReturn($packer);
$handler->method('getPacker')->willReturn($packer);

$defaultResponse = DummyFactory::createEmptyResponse();

if (!$this->requests->count()) {
$handler->handle(Argument::type(Request::class))->willReturn($defaultResponse);
$handler->method('handle')->willReturn($defaultResponse);

return $handler;
}

foreach ($this->requests as $request) {
if (!$responses = $this->requests->getInfo()) {
$handler->handle($request)->willReturn($defaultResponse);
$handler->method('handle')->with($request)->willReturn($defaultResponse);
continue;
}

$handler->handle($request)->willReturn(...$responses)
->shouldBeCalledTimes(\count($responses));
$handler->expects(TestCase::exactly(\count($responses)))
->method('handle')->with($request)
->willReturnOnConsecutiveCalls(...$responses);
}

return $handler;
}

/**
* @return Connection|ObjectProphecy
* @return Connection|MockObject
*/
private function createConnection()
{
if ($this->connection) {
return $this->connection;
}

return ($this->prophesize)(Connection::class);
return $this->createMock(Connection::class);
}

/**
* @return Packer|ObjectProphecy
* @return Packer|MockObject
*/
private function createPacker()
{
if ($this->packer) {
return $this->packer;
}

return ($this->prophesize)(Packer::class);
return $this->createMock(Packer::class);
}

/**
* @param class-string $originalClassName
*/
private function createMock(string $originalClassName) : MockObject
{
return $this->testCase->getMockBuilder($originalClassName)
->disableOriginalConstructor()
->disableOriginalClone()
->disableArgumentCloning()
->disallowMockingUnknownTypes()
->getMock();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

use PHPUnit\Framework\TestCase;
use PHPUnitExtras\Expectation\ExpressionContext;
use Prophecy\Argument;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Tarantool\Client\RequestTypes;
use Tarantool\PhpUnit\Client\ClientMocking;
use Tarantool\PhpUnit\Client\DummyFactory;
use Tarantool\PhpUnit\Client\IsRequestType;
use Tarantool\PhpUnit\Expectation\ExpressionContext\RequestCountContext;
use Tarantool\PhpUnit\Expectation\ExpressionContext\RequestCounter;

Expand All @@ -31,7 +31,7 @@ public function testGetValuesReturnsCorrectValues() : void
{
$mockClient = $this->getMockClientBuilder()
->shouldHandle(
Argument::which('getType', RequestTypes::EVALUATE),
new IsRequestType(RequestTypes::EVALUATE),
DummyFactory::createResponseFromData([2]),
DummyFactory::createResponseFromData([3])
)->build();
Expand Down

0 comments on commit f9bdc0c

Please sign in to comment.