Tajuk yang ditulis semula ialah: Bagaimanakah saya boleh mensimulasikan pengirim Symfony untuk tujuan ujian?
P粉739706089
P粉739706089 2023-12-13 09:42:22
0
2
486

Saya menggunakan pengirim Symfony dalam kelas tersuai dalam projek Symfony 6. Saya menggunakan pendawaian automatik melalui petunjuk jenis dalam pembina kelas seperti ini:

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,
                ];
            }
        }
    }

Panggil kaedah sendEmail() dalam pengawal dan semuanya berfungsi dengan baik.

Sekarang saya mahu menguji TransportExceptions 是否被正确处理。为此,我需要邮件程序在我的测试中抛出 TransportExceptions. Walau bagaimanapun, ini tidak berjaya seperti yang saya harapkan.

NOTA : Saya tidak boleh membuang pengecualian dengan menghantar alamat e-mel yang tidak sah kerana kaedah sendMail hanya membenarkan alamat e-mel yang sah.

Perkara yang saya pernah cuba:

1) Gunakan program e-mel simulasi

// 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);

Ternyata saya tidak dapat mensimulasikan Mailer 类,因为它是 final.

2) Gunakan olok-olok (atau rintisan) MailerInterface

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

Tiada ralat, tetapi tiada pengecualian yang dilemparkan. Perkhidmatan mel nampaknya tidak diganti.

3) Gunakan kelas MailerExceptionTester tersuai

// 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();
    }
}

Dalam ujian:

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

Hasil yang sama seperti dalam 2)

4) Cuba tukar perkhidmatan MailerInterface dan bukannya Mailer

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

Mesej ralat: SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服务是私有的,您无法替换它。

5) Tetapkan Antaramuka Mailer kepada umum

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

错误:无法实例化接口 SymfonyComponentMailerMailerInterface

6) Tambahkan alias untuk MailerInterface

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

Mesej ralat: SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服务是私有的,您无法替换它。

Bagaimana untuk menggantikan perkhidmatan MailerInterface yang disambungkan secara automatik dalam ujian?

P粉739706089
P粉739706089

membalas semua(2)
P粉704066087

Tempahan hendaklah betul pada percubaan pertama anda.

// 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');

Tidak diuji, tetapi anda mendapat kelas sebagai objek, jadi kebergantungan pada perkhidmatan sudah diselesaikan sebelum mengejek. Ini sepatutnya menggantikan perkhidmatan dalam bekas dahulu dan kemudian dapatkan MyClass dari bekas.

Namun, anda juga boleh melangkau membina bekas sepenuhnya. Hanya gunakan PhpUnit.

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

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

Saya cuba melakukan ini dan saya percaya saya telah menemui penyelesaian berdasarkan perkara yang telah anda cuba.

Dalam perkhidmatan services.yaml 中,我重新声明 mailer.mailer saya dan tetapkannya kepada umum dalam persekitaran ujian:

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

Persediaan ini sepatutnya menjadikan perkhidmatan Symfony Mailer berkelakuan sama seperti dahulu, tetapi kerana ia kini terbuka, kami boleh mengatasi kelas yang digunakan dalam bekas jika diperlukan.

Saya menyalin kelas Mailer tersuai yang anda tulis...

// MailerExceptionTester.php

...dalam kod ujian saya, saya mengambil bekas ujian dan menggantikan perkhidmatan mailer.mailer dengan contoh kelas melontar pengecualian:

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

Kini, setiap kali anda menyuntik perkhidmatan Mailer, kelas yang digunakan akan menjadi kelas melontar pengecualian tersuai!

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!