Skip to content

Commit 324586c

Browse files
committed
[FrameworkBundle] PhpUnit assert Messenger
1 parent d6c8797 commit 324586c

File tree

15 files changed

+399
-0
lines changed

15 files changed

+399
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
6.4
55
---
66

7+
* Add `MessengerAssertionsTrait`
78
* Add `HttpClientAssertionsTrait`
89
* Add `AbstractController::renderBlock()` and `renderBlockView()`
910
* Add native return type to `Translator` and to `Application::reset()`

src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Messenger\Bridge\Redis\Transport\RedisTransportFactory;
1919
use Symfony\Component\Messenger\EventListener\AddErrorDetailsStampListener;
2020
use Symfony\Component\Messenger\EventListener\DispatchPcntlSignalListener;
21+
use Symfony\Component\Messenger\EventListener\MessagesSentToTransportsListener;
2122
use Symfony\Component\Messenger\EventListener\ResetServicesListener;
2223
use Symfony\Component\Messenger\EventListener\SendFailedMessageForRetryListener;
2324
use Symfony\Component\Messenger\EventListener\SendFailedMessageToFailureTransportListener;
@@ -232,5 +233,8 @@
232233
service('messenger.default_bus'),
233234
])
234235
->tag('messenger.message_handler')
236+
237+
->set('messenger.sent_messages_to_transport_listener', MessagesSentToTransportsListener::class)
238+
->tag('kernel.event_subscriber')
235239
;
236240
};

src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
abstract class KernelTestCase extends TestCase
2727
{
2828
use MailerAssertionsTrait;
29+
use MessengerAssertionsTrait;
2930
use NotificationAssertionsTrait;
3031

3132
protected static $class;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Test;
13+
14+
use Symfony\Component\Messenger\EventListener\MessagesSentToTransportsListener;
15+
use Symfony\Component\Messenger\Test\Constraint as MessengerConstraint;
16+
17+
/*
18+
* @author Marilena Ruffelaere <marilena.ruffelaere@gmail.com>
19+
*/
20+
21+
trait MessengerAssertionsTrait
22+
{
23+
/**
24+
* @param int $count the expected number of messages
25+
* @param string|null $busName The busName to consider. If null all the collected messages will be counted.
26+
*/
27+
public static function assertMessagesByBusCount(int $count, string $busName = null, string $message = ''): void
28+
{
29+
self::assertThat(self::getDispatchedMessagesByBusName($busName), new MessengerConstraint\MessageCount($count, $busName), $message);
30+
}
31+
32+
/**
33+
* @param int $count the expected number of messages of the given class
34+
* @param string $className the message object class name
35+
*/
36+
public static function assertMessagesOfClassCount(int $count, string $className, string $message = ''): void
37+
{
38+
self::assertThat(self::getDispatchedMessagesByClassName($className), new MessengerConstraint\MessageCount($count, $className), $message);
39+
}
40+
41+
public static function getDispatchedMessagesByBusName(?string $busName, bool $ordered = false): array
42+
{
43+
$container = static::getContainer();
44+
if ($container->has('messenger.sent_messages_to_transport_listener')) {
45+
/** @var MessagesSentToTransportsListener $listener */
46+
$listener = $container->get('messenger.sent_messages_to_transport_listener');
47+
48+
return array_column($listener->getSentMessagesByBus($busName), 'message');
49+
}
50+
static::fail('A client must have Messenger enabled to make messages assertions .
51+
Did you forget to require symfony/messenger ?');
52+
}
53+
54+
public static function getDispatchedMessagesByClassName(string $className): array
55+
{
56+
$container = static::getContainer();
57+
58+
if ($container->has('messenger.sent_messages_to_transport_listener')) {
59+
/** @var MessagesSentToTransportsListener $listener */
60+
$listener = $container->get('messenger.sent_messages_to_transport_listener');
61+
62+
return array_column($listener->getSentMessagesByClassName($className), 'message');
63+
}
64+
static::fail('A client must have Messenger enabled to make messages assertions.
65+
Did you forget to require symfony/messenger ? ');
66+
}
67+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger;
13+
14+
class DummyCommand
15+
{
16+
public function __construct(private readonly string $message)
17+
{
18+
}
19+
20+
public function getMessage(): string
21+
{
22+
return $this->message;
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger;
13+
14+
class DummyQuery
15+
{
16+
public function __construct(private readonly string $message)
17+
{
18+
}
19+
20+
public function getMessage(): string
21+
{
22+
return $this->message;
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller;
13+
14+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyCommand;
15+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyMessage;
16+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyQuery;
17+
use Symfony\Component\HttpFoundation\Response;
18+
use Symfony\Component\Messenger\Envelope;
19+
use Symfony\Component\Messenger\MessageBusInterface;
20+
21+
/*
22+
* @author Marilena Ruffelaere <marilena.ruffelaere@gmail.com>
23+
*/
24+
25+
class MessengerController
26+
{
27+
public function indexAction(MessageBusInterface $bus, MessageBusInterface $queryBus): Response
28+
{
29+
$queryBus->dispatch(new Envelope(message: new DummyMessage('dummy message text'), stamps: []));
30+
31+
$queryBus->dispatch(new DummyQuery('First Dummy Query message'));
32+
33+
$bus->dispatch(new DummyCommand('First Dummy Command message'));
34+
35+
$queryBus->dispatch(new DummyQuery('Still searching?'));
36+
37+
$queryBus->dispatch(new DummyQuery('Stop searching, Symfony is amazing!'));
38+
39+
$bus->dispatch(new DummyCommand('Second Dummy Command message'));
40+
41+
return new Response();
42+
}
43+
}

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,7 @@ uid:
7272
send_notification:
7373
path: /send_notification
7474
defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\NotificationController::indexAction }
75+
76+
send_messenger_message:
77+
path: /send_messenger_message
78+
defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\MessengerController::indexAction }
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
13+
14+
/*
15+
* @author Marilena Ruffelaere <marilena.ruffelaere@gmail.com>
16+
*/
17+
18+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyCommand;
19+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyMessage;
20+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyQuery;
21+
22+
final class MessengerTest extends AbstractWebTestCase
23+
{
24+
public function testMessengerAssertion()
25+
{
26+
$client = $this->createClient(['test_case' => 'Messenger', 'root_config' => 'config.yml', 'debug' => true]);
27+
$response = $client->request('GET', '/send_messenger_message');
28+
29+
$this->assertMessagesByBusCount(6);
30+
$this->assertMessagesByBusCount(2, 'event.bus');
31+
$this->assertMessagesByBusCount(4, 'query.bus');
32+
33+
$this->assertMessagesOfClassCount(2, DummyCommand::class);
34+
$this->assertMessagesOfClassCount(3, DummyQuery::class);
35+
$this->assertMessagesOfClassCount(1, DummyMessage::class);
36+
37+
/** @var DummyMessage[] $dummyMessages */
38+
$dummyMessages = $this::getDispatchedMessagesByClassName(DummyMessage::class);
39+
self::assertCount(1, $dummyMessages);
40+
self::assertStringContainsString('dummy message text', $dummyMessages[0]->getMessage());
41+
42+
$messagesFromQueryBus = $this::getDispatchedMessagesByBusName('query.bus');
43+
self::assertCount(4, $messagesFromQueryBus);
44+
45+
self::assertInstanceOf(DummyMessage::class, $messagesFromQueryBus[0]);
46+
47+
/* @var DummyQuery $firstQuery */
48+
self::assertInstanceOf(DummyQuery::class, $firstQuery = $messagesFromQueryBus[1]);
49+
self::assertStringContainsString('First Dummy Query message', $firstQuery->getMessage());
50+
}
51+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
13+
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
14+
15+
return [
16+
new FrameworkBundle(),
17+
new TestBundle(),
18+
];
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
imports:
2+
- { resource: ../config/default.yml }
3+
- { resource: services.yml }
4+
5+
framework:
6+
7+
messenger:
8+
default_bus: event.bus
9+
10+
buses:
11+
event.bus:
12+
default_middleware:
13+
allow_no_handlers: true
14+
15+
query.bus:
16+
default_middleware:
17+
allow_no_handlers: true
18+
19+
transports:
20+
sync: 'sync://'
21+
22+
routing:
23+
'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyQuery': 'sync'
24+
'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyCommand': 'sync'
25+
'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyMessage': 'sync'
26+
27+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
_messengertest_bundle:
2+
resource: '@TestBundle/Resources/config/routing.yml'
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
services:
3+
_defaults:
4+
public: true
5+
6+
7+
Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\MessengerController:
8+
tags: ['controller.service_arguments']
9+
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
/*
13+
* This file is part of the Symfony package.
14+
*
15+
* (c) Fabien Potencier <fabien@symfony.com>
16+
*
17+
* For the full copyright and license information, please view the LICENSE
18+
* file that was distributed with this source code.
19+
*/
20+
21+
namespace Symfony\Component\Messenger\EventListener;
22+
23+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
24+
use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent;
25+
use Symfony\Component\Messenger\Stamp\BusNameStamp;
26+
use Symfony\Contracts\Service\ResetInterface;
27+
28+
/*
29+
* @author Marilena Ruffelaere <marilena.ruffelaere@gmail.com>
30+
*/
31+
32+
class MessagesSentToTransportsListener implements EventSubscriberInterface, ResetInterface
33+
{
34+
private array $sentMessages = [];
35+
36+
public static function getSubscribedEvents(): array
37+
{
38+
return [
39+
SendMessageToTransportsEvent::class => ['onMessageSent', -255],
40+
];
41+
}
42+
43+
public function onMessageSent(SendMessageToTransportsEvent $event): void
44+
{
45+
$envelope = $event->getEnvelope();
46+
$this->sentMessages[] = [
47+
'busName' => $envelope->last(BusNameStamp::class)->getBusName(),
48+
'message' => $envelope->getMessage(),
49+
];
50+
}
51+
52+
public function getSentMessages(): array
53+
{
54+
return $this->sentMessages;
55+
}
56+
57+
public function getSentMessagesByBus(?string $busName): array
58+
{
59+
if (null === $busName) {
60+
return $this->getSentMessages();
61+
}
62+
63+
return array_filter($this->sentMessages, fn ($message) => $message['busName'] === $busName);
64+
}
65+
66+
public function getSentMessagesByClassName(?string $className): array
67+
{
68+
if (null === $className) {
69+
return $this->getSentMessages();
70+
}
71+
72+
return array_filter($this->sentMessages, fn ($message) => $message['message']::class === $className);
73+
}
74+
75+
public function reset(): void
76+
{
77+
$this->sentMessages = [];
78+
}
79+
}

0 commit comments

Comments
 (0)