Le titre réécrit est : Comment puis-je simuler le mailer Symfony à des fins de test ?
P粉739706089
P粉739706089 2023-12-13 09:42:22
0
2
511

J'utilise le mailer Symfony dans une classe personnalisée dans un projet Symfony 6. J'utilise le câblage automatique via des indices de type dans le constructeur de la classe comme ceci :

class MyClass {
        public function __construct(private readonly MailerInterface $mailer) {}


        public function sendEmail(): array
        {
            // Email is sent down here
            try {
                $this->mailer->send($email);
            
                return [
                    'success' => true,
                    'message' => 'Email sent',
                ];
            } catch (TransportExceptionInterface $e) {
                return [
                    'success' => false,
                    'message' => 'Error sending email: ' . $e,
                ];
            }
        }
    }

Appelez la méthode sendEmail() dans le contrôleur et tout fonctionne bien.

Maintenant, je veux tester les TransportExceptions 是否被正确处理。为此,我需要邮件程序在我的测试中抛出 TransportException. Cependant, cela n’a pas fonctionné comme je l’espérais.

REMARQUE  : Je ne peux pas lever d'exception en transmettant une adresse e-mail invalide car la méthode sendMail n'autorise que les adresses e-mail valides.

Choses que j'ai essayées :

1) Utilisez un programme de messagerie simulé

// boot kernel and get Class from container
$container = self::getContainer();
$myClass = $container->get('AppModelMyClass');

// create mock mailer service
$mailer = $this->createMock(Mailer::class);
$mailer->method('send')
        ->willThrowException(new TransportException());
$container->set('SymfonyComponentMailerMailer', $mailer);

Il s'est avéré que je ne pouvais pas simuler Mailer 类,因为它是 final.

2) Utilisez une maquette (ou un stub) MailerInterface

// create mock mailer service
$mailer = $this->createStub(MailerInterface::class);
$mailer->method('send')
        ->willThrowException(new TransportException());
$container->set('SymfonyComponentMailerMailer', $mailer);

Aucune erreur, mais aucune exception levée. Le service de messagerie ne semble pas avoir été remplacé.

3) Utilisez la classe MailerExceptionTester personnalisée

// MailerExceptionTester.php
<?php

namespace AppTests;

use SymfonyComponentMailerEnvelope;
use SymfonyComponentMailerExceptionTransportException;
use SymfonyComponentMailerMailerInterface;
use SymfonyComponentMimeRawMessage;

/**
 * Always throws a TransportException
 */
final class MailerExceptionTester implements MailerInterface
{
    public function send(RawMessage $message, Envelope $envelope = null): void
    {
        throw new TransportException();
    }
}

En test :

// create mock mailer service
$mailer = new MailerExceptionTester();
$container->set('SymfonyComponentMailerMailer', $mailer);

Même résultat qu'en 2)

4) Essayez de changer le service MailerInterface au lieu de Mailer

// create mock mailer service
$mailer = $this->createMock(MailerInterface::class);
$mailer->method('send')
        ->willThrowException(new TransportException());
$container->set('SymfonyComponentMailerMailerInterface', $mailer);

Message d'erreur : SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服务是私有的,您无法替换它。

5) Définissez MailerInterface sur public

// services.yaml
services:
    SymfonyComponentMailerMailerInterface:
        public: true

错误:无法实例化接口 SymfonyComponentMailerMailerInterface

6) Ajouter un alias pour MailerInterface

// services.yaml
services:
    app.mailer:
        alias: SymfonyComponentMailerMailerInterface
        public: true

Message d'erreur : SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服务是私有的,您无法替换它。

Comment remplacer un service MailerInterface automatiquement connecté dans un test ?

P粉739706089
P粉739706089

répondre à tous(2)
P粉704066087

La commande devrait être correcte dès votre premier essai.

// boot kernel and get Class from container
$container = self::getContainer();
$container->set('Symfony\Component\Mailer\Mailer', $mailer);

// create mock mailer service
$mailer = $this->createMock(Mailer::class);
$mailer->method('send')
        ->willThrowException(new TransportException());

$myClass = $container->get('App\Model\MyClass');

Non testé, mais vous obtenez la classe en tant qu'objet, donc les dépendances sur le service sont déjà résolues avant de se moquer. Cela devrait d'abord remplacer le service dans le conteneur, puis récupérer MyClass du conteneur.

Cependant, vous pouvez également ignorer complètement la construction du conteneur. Utilisez simplement PhpUnit.

$mock = $this->createMock(Mailer::class);
// ... 

$myClass = new MyClass($mock);
$myClass->sendEmail();
P粉226667290

J'essaie de faire cela et je crois avoir trouvé une solution basée sur ce que vous avez déjà essayé.

Dans mon services.yaml 中,我重新声明 mailer.mailer service et rendez-le public dans l'environnement de test :

when@test:
    services:
        mailer.mailer:
            class: Symfony\Component\Mailer\Mailer
            public: true
            arguments:
                - '@mailer.default_transport'

Cette configuration devrait permettre au service Symfony Mailer de se comporter exactement de la même manière qu'avant, mais comme il est désormais public, nous pouvons remplacer les classes qu'il utilise dans le conteneur si nécessaire.

J'ai copié la classe Mailer personnalisée que vous avez écrite...

// MailerExceptionTester.php

...dans mon code de test, j'ai pris le conteneur de test et remplacé le service mailer.mailer par une instance de la classe de lancement d'exception :

$mailer = new MailerExceptionTester();
static::getContainer()->set('mailer.mailer', $mailer);

Désormais, chaque fois que vous injecterez le service Mailer, la classe utilisée sera une classe de lancement d'exception personnalisée !

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!