Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test Symfony Messenger

I've been messing around with implementing AMQP using Symfony Messenger in my latest project. While the code works to my great joy i am unable to write unit tests for methods which dispatches messages.

All my tests involving code that dispatch message result in the following warnings:

Class "Symfony\Component\Messenger\Envelope" is declared "final" and cannot be mocked.

I am unable to find documentation on Symfony's site covering Tests on Symfony Messenger.

How can i test my code with unit tests involving messages?

Class:

namespace App\MessageHandler;

use App\Entity\File;
use App\Message\CheckVideoMessage;
use App\Message\GenerateThumbnailMessage;
use App\Message\GetVideoMetadataMessage;
use App\Message\ProcessFileMessage;
use App\Service\MediaProcessorService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Messenger\MessageBusInterface;

class ProcessFileMessageHandler
{
    /**
     * @var MediaProcessorService
     */
    private $mediaProcessorService;

    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var MessageBusInterface
     */
    private $messageBus;

    public function __construct(
        MediaProcessorService $mediaProcessorService,
        EntityManagerInterface $entityManager,
        LoggerInterface $logger,
        MessageBusInterface $messageBus
    ) {
        $this->mediaProcessorService = $mediaProcessorService;
        $this->entityManager         = $entityManager;
        $this->logger                = $logger;
        $this->messageBus            = $messageBus;
    }

    public function __invoke(ProcessFileMessage $message)
    {
        /** @var File $file */
        $file = $this->entityManager->find(File::class, $message->getFileId());

        if (!$file->getInode()->getMeta()) {
            $this->messageBus->dispatch(new GetVideoMetadataMessage($file->getId()));
        }

        // This event will also dispatch message to generate thumbnails if the video is valid
        $this->messageBus->dispatch(new CheckVideoMessage($file->getId()));

        $this->messageBus->dispatch(new GenerateThumbnailMessage($file->getId()));
    }
}

TestFile:

namespace App\Tests\MessageHandler;

use App\Entity\Inode;
use App\MessageHandler\ProcessFileMessageHandler;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use App\Entity\File;
use App\Message\CheckVideoMessage;
use App\Message\GenerateThumbnailMessage;
use App\Message\GetVideoMetadataMessage;
use App\Message\ProcessFileMessage;
use App\Service\MediaProcessorService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Messenger\MessageBusInterface;

class ProcessFileMessageHandlerTest extends TestCase
{
    /**
     * @var MediaProcessorService|MockObject
     */
    private $mediaProcessorService;

    /**
     * @var EntityManagerInterface|MockObject
     */
    private $entityManager;

    /**
     * @var LoggerInterface|MockObject
     */
    private $logger;

    /**
     * @var MessageBusInterface|MockObject
     */
    private $messageBus;

    /**
     * @var ProcessFileMessageHandler
     */
    private $handler;

    protected function setUp()
    {
        $this->mediaProcessorService = $this->getMockBuilder(MediaProcessorService::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->entityManager = $this->getMockBuilder(EntityManagerInterface::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->logger = $this->getMockBuilder(LoggerInterface::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->messageBus = $this->getMockBuilder(MessageBusInterface::class)
            ->disableOriginalConstructor()
            ->getMock();

        $this->handler = new ProcessFileMessageHandler(
            $this->mediaProcessorService,
            $this->entityManager,
            $this->logger,
            $this->messageBus
        );
    }

    /**
     * @test
     */
    public function willDispatchAllMessagesOnANewFile()
    {
        $message = new ProcessFileMessage(1);
        $inode   = (new Inode())->setMeta(false);
        $file = (new File())->setId(1)->setInode($inode);

        $this->entityManager->expects($this->once())
            ->method('find')
            ->willReturn($file);

        $this->messageBus->expects(self::exactly(3))
            ->method('dispatch')
            ->withConsecutive(
                self::isInstanceOf(GetVideoMetadataMessage::class),
                self::isInstanceOf(CheckVideoMessage::class),
                self::isInstanceOf(GenerateThumbnailMessage::class)
            );

        $handler = $this->handler;
        $handler($message);
    }
}
like image 299
PBX_g33k Avatar asked Jan 09 '19 21:01

PBX_g33k


Video Answer


1 Answers

Problem was resolved by setting a return with an Envelope object.

    $this->messageBus->expects(self::exactly(3))
        ->method('dispatch')
        ->withConsecutive(
            self::isInstanceOf(GetVideoMetadataMessage::class),
            self::isInstanceOf(CheckVideoMessage::class),
            self::isInstanceOf(GenerateThumbnailMessage::class)
        )
        ->willReturn(new Symfony\Component\Messenger\Envelope($message));
like image 198
PBX_g33k Avatar answered Oct 04 '22 05:10

PBX_g33k