messenger-test: Undefined array key "" when running multiple test

Hello,

I have an error when running multiple tests. What I mean by “running multiple tests” is when launching test over a test file with multiple testFunction().

App\Tests\Functional\Review\StatisticsReviewResourceTest::testIncrementNumberOfRefdusedByReviewer
Undefined array key "statistic"

/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:349
/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:266
/var/www/vendor/symfony/messenger/Middleware/SendMessageMiddleware.php:68
/var/www/vendor/symfony/messenger/Middleware/FailedMessageProcessingMiddleware.php:34
/var/www/vendor/symfony/messenger/Middleware/DispatchAfterCurrentBusMiddleware.php:68
/var/www/vendor/symfony/messenger/Middleware/RejectRedeliveredMessageMiddleware.php:41
/var/www/vendor/symfony/messenger/Middleware/AddBusNameStampMiddleware.php:37
/var/www/vendor/symfony/messenger/Middleware/TraceableMiddleware.php:40
/var/www/vendor/symfony/messenger/MessageBus.php:70
/var/www/vendor/symfony/messenger/TraceableMessageBus.php:38
/var/www/vendor/zenstruck/messenger-test/src/Bus/TestBus.php:38
/var/www/src/Statistics/Listener/NumberOfReviewersCreatedListener.php:20
/var/www/vendor/doctrine/orm/lib/Doctrine/ORM/Event/ListenersInvoker.php:93
/var/www/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:1175
/var/www/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:431
/var/www/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:403
/var/www/vendor/zenstruck/foundry/src/Proxy.php:147
/var/www/vendor/zenstruck/foundry/src/Factory.php:151
/var/www/vendor/zenstruck/foundry/src/FactoryCollection.php:77
/var/www/vendor/zenstruck/foundry/src/ModelFactory.php:39
/var/www/tests/Functional/Review/StatisticsReviewResourceTest.php:88

These are the class dispatching messages :

#[AsEntityListener(event: Events::postPersist, entity: Reviewer::class)]
class NumberOfReviewersCreatedListener
{
    public function __construct(private readonly MessageBusInterface $messageBus)
    {
    }

    public function __invoke(Reviewer $reviewer): void
    {
        $this->messageBus->dispatch(new StatisticsReviewNumberOfReviewersCreatedMessage($reviewer->getCompany()));
    }
}
#[AsEntityListener(event: Events::preRemove, entity: Reviewer::class)]
class NumberOfRefusedByReviewerListener
{
    public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security)
    {
    }

    public function __invoke(Reviewer $reviewer): void
    {
        if ($this->security->getUser() instanceof Reviewer) {
            $this->messageBus->dispatch(new StatisticsReviewNumberOfRefusedByReviewerMessage($reviewer->getCompany()));
        }
    }
}
#[AsEntityListener(event: Events::preRemove, entity: Reviewer::class)]
class NumberOfDeletedListener
{
    public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security)
    {
    }

    public function __invoke(Reviewer $reviewer): void
    {
        if (!$this->security->getUser() instanceof Reviewer) {
            $this->messageBus->dispatch(new StatisticsReviewNumberOfDeletedReviewersMessage($reviewer->getCompany()));
        }
    }
}

My test file

class StatisticsReviewResourceTest extends ApiTestCase
{
    public function testIncrementNumberOfReviewersCreated()
    {
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals(0, $statistics->getNumberOfReviewersCreated());

        $numberOfReviewersToCreate = 4;
        ReviewerFactory::createMany($numberOfReviewersToCreate, [
            'company' => $this->company
        ]);

        $this->transport('statistic')->queue()->assertCount($numberOfReviewersToCreate);
        $this->transport('statistic')->queue()->assertContains(StatisticsReviewNumberOfReviewersCreatedMessage::class, $numberOfReviewersToCreate);
        $this->transport('statistic')->process();

        $this->company->refresh();
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals($numberOfReviewersToCreate, $statistics->getNumberOfReviewersCreated());
    }

    public function testIncrementNumberOfRefusedByReviewer()
    {
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals(0, $statistics->getNumberOfRefusedByReviewer());

        ReviewerFactory::createMany(3, [
            'company' => $this->company
        ]);
        $this->transport('statistic')->process();

        $reviewer = ReviewerFactory::first();
        $this->browser()
            ->actingAs($reviewer)
            ->delete('/api/reviewers/'.$reviewer->getUuid())
            ->assertStatus(204);

        $this->transport('statistic')->queue()->assertCount(1);
        $this->transport('statistic')->queue()->assertContains(StatisticsReviewNumberOfRefusedByReviewerMessage::class, 1);
        $this->transport('statistic')->process();

        $this->company->refresh();
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals(1, $statistics->getNumberOfRefusedByReviewer());
    }

    public function testIncrementNumberOfDeletedReviewers()
    {
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals(0, $statistics->getNumberOfDeletedReviewer());

        ReviewerFactory::createMany(3, [
            'company' => $this->company
        ]);
        $this->transport('statistic')->process();

        $reviewer = ReviewerFactory::first();
        $this->browser()
            ->actingAs($this->owner)
            ->delete('/api/reviewers/'.$reviewer->getUuid())
            ->assertStatus(204);

        $this->transport('statistic')->queue()->assertCount(1);
        $this->transport('statistic')->queue()->assertContains(StatisticsReviewNumberOfDeletedReviewersMessage::class, 1);
        $this->transport('statistic')->process();

        $this->company->refresh();
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals(1, $statistics->getNumberOfDeletedReviewer());
    }

    public function testJustForEvenNumberFail()
    {
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals(0, $statistics->getNumberOfRefusedByReviewer());

        ReviewerFactory::createMany(3, [
            'company' => $this->company
        ]);
        $this->transport('statistic')->process();

        $reviewer = ReviewerFactory::first();
        $this->browser()
            ->actingAs($reviewer)
            ->delete('/api/reviewers/'.$reviewer->getUuid())
            ->assertStatus(204);

        $this->transport('statistic')->queue()->assertCount(1);
        $this->transport('statistic')->queue()->assertContains(StatisticsReviewNumberOfRefusedByReviewerMessage::class, 1);
        $this->transport('statistic')->process();

        $this->company->refresh();
        $statistics = $this->company->getStatisticsReview();
        $this->assertEquals(1, $statistics->getNumberOfRefusedByReviewer());
    }
}
abstract class ApiTestCase extends \ApiPlatform\Symfony\Bundle\Test\ApiTestCase
{
    use HasBrowser {
        browser as baseKernelBrowser;
    }

    use CompanyTestTrait;
    use HasCompany;
    use InteractsWithMessenger;
    use ResetDatabase;
    use Factories;

    protected function browser(array $options = [], array $server = []): TestBrowser
    {
        return $this->baseKernelBrowser($options, $server)
            ->setDefaultHttpOptions(
                HttpOptions::create()
                    ->withHeader('Accept', 'application/ld+json')
            );
    }
}
  • If I run my test separately with --filter they all pass without error. But when launching the entire file, I got this error on the second test and fourth test (all even number).
  • if I remove the dispatch from the NumberOfDeletedListener everything works but not the third test who test the functionality related to this dispatch
  • if I change the order of the test : it is still the second and fourth that fail
  • I have nothing in the log or in the browser error output
  • I have many other tests using messenger that run perfectly even when multiple test in one file and other listeners, but only this one fail like that

If I remove the dispatch from NumberOfReviewersCreatedListener.php:20 I got the same error but slightly different and on all tests (2, 3 , 4) (first test fail cause there is no more message dispatched)

1) App\Tests\Functional\Review\StatisticsReviewResourceTest::testIncrementNumberOfRefusedByReviewer
Undefined array key "statistic"

/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:339
/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:164
/var/www/tests/Functional/Review/StatisticsReviewResourceTest.php:40

2) App\Tests\Functional\Review\StatisticsReviewResourceTest::testIncrementNumberOfDeletedReviewers
Undefined array key "statistic"

/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:339
/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:164
/var/www/tests/Functional/Review/StatisticsReviewResourceTest.php:65

3) App\Tests\Functional\Review\StatisticsReviewResourceTest::testJustForEvenNumberFail
Undefined array key "statistic"

/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:339
/var/www/vendor/zenstruck/messenger-test/src/Transport/TestTransport.php:164
/var/www/tests/Functional/Review/StatisticsReviewResourceTest.php:90

If one you got an idea of what happening it would be a great help ! Thanks

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

Ok, I believe the issue was with your tearDown() not calling parent::tearDown().

Again though, you shouldn’t need to delete entities in tearDown(), @after methods when using the ResetDatabase trait.

If you want to keep the tearDown method, ensure parent::tearDown() is called after your logic.

Maybe it’s not the good way, but I like to keep all my environments as clean as possible and at the same time check if users can delete their companies environments (through api call) what ever they are doing (all my other tests)

That makes perfect sense.

I still don’t understand why this happens to this particular test with those PreRemove hooks triggered. It is because the kernel was not shutdown properly, so the reset messenger get wrong ? But what the link between this and the hooks …

I think the issue is the methods marked as @after are called after tearDown (which shuts down the kernel)