Improve testing integration
rvitaliy opened this issue · 5 comments
Hi!
My problem is that Symfony\Component\Mercure\Publisher
is final
, so i can't mock it with Prophecy\Prophecy\ObjectProphecy
.
I suggest to add an interface and use it as typehint instead of concrete final class.
what do you think?
As it's just an invokable class (__invoke
), you can mock it using any callable
(a function, a closure, an invokable class...).
I can't understand how a invocable class can resolve my issue.
I try to write my test example to explain it better.
NB: I prefer use Publisher
as a service and don't hard code it on my services.
my service class:
<?php
declare(strict_types=1);
use Symfony\Component\Mercure\Publisher;
use Symfony\Component\Mercure\Update;
final class MyClass
{
/**
* @var Publisher
*/
private $publisher;
public function __construct(Publisher $publisher)
{
$this->publisher = $publisher;
}
public function execute(bool $notifyToCustomer): void
{
if ($notifyToCustomer) {
$this->publisher->__invoke(
new Update(
'topic',
'data',
['target']
)
);
}
}
}
my test class:
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Symfony\Component\Mercure\Publisher;
final class MyClassTest extends TestCase
{
/**
* @var MyClass
*/
private $myClass;
/**
* @var ObjectProphecy<Publisher>
*/
private $publisher;
protected function setUp(): void
{
parent::setUp();
$this->publisher = $this->prophesize(Publisher::class);
$this->myClass = new MyClass(
$this->publisher->reveal()
);
}
public function testExecuteNotifyToCustomer(): void
{
$this->publisher
->__invoke(Argument::cetera())
->shouldBeCalledOnce();
$this->myClass->execute(true);
}
public function testExecuteDontNotifyToCustomer(): void
{
$this->publisher
->__invoke(Argument::cetera())
->shouldNotBeCalled();
$this->myClass->execute(false);
}
}
@rvitaliy Create your own interface PublisherInterface for example with a method 'publish', then create an implementation of that interface and inject publisher (mercure instance).
class MyPublisher implement PublisherInterface
{
public function __construct(Mercure\Namespace\Publisher $publisher)
{
$this->publisher = $publisher;
}
public function publish($message)
{
$this->publisher->__invoke($message);
}
}
Then in your test, mock the interface...