繁体   English   中英

Symfony 功能测试 - 如何使用请求模拟控制器注入的服务(提交)

[英]Symfony Functional Testing - How to mock controller injected service with request(submit)

如何在发出“请求”(表单/提交)的功能测试用例中模拟服务。 发出请求后,我对容器所做的所有更改和模拟都丢失了。

我正在使用 Symfony 4 或 5。这里发布的代码也可以在这里找到: https : //github.com/klodoma/symfony-demo

我有以下场景:

  • SomeActions服务被注入到控制器构造函数中
  • 在功能单元测试中,我尝试模拟SomeActions函数以检查它们是否已执行(它发送电子邮件或类似的东西)

我模拟服务并在单元测试中覆盖它:

$container->set('App\Model\SomeActions', $someActions);

现在在测试中我做了一个$client->submit($form); 我知道它终止了内核。

我的问题是:如何在$client->submit($form);之后将我模拟$someActions注入容器中$client->submit($form);

下面是我添加到 symfony 演示应用程序的示例代码https://github.com/symfony/demo

在此处输入图片说明

在 services.yaml 中

App\Model\SomeActions:
    public: true

一些控制器.php

<?php

namespace App\Controller;

use App\Model\SomeActions;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Controller used to send some emails
 *
 * @Route("/some")
 */
class SomeController extends AbstractController
{
    private $someActions;

    public function __construct(SomeActions $someActions)
    {
        //just dump the injected class name
        var_dump(get_class($someActions));

        $this->someActions = $someActions;
    }

    /**
     * @Route("/action", methods="GET|POST", name="some_action")
     * @param Request $request
     * @return Response
     */
    public function someAction(Request $request): Response
    {

        $this->someActions->doSomething();

        if ($request->get('send')) {
            $this->someActions->sendEmail();
        }

        return $this->render('default/someAction.html.twig', [
        ]);
    }
}

一些动作

<?php

namespace App\Model;

use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;

class SomeActions
{
    private $mailer;

    public function __construct(MailerInterface $mailer)
    {
        $this->mailer = $mailer;
    }

    public function doSomething()
    {
        echo 'doSomething';
    }

    public function sendEmail()
    {
        echo 'sendEmail';

        $email = (new Email())
            ->from('hello@example.com')
            ->to('you@example.com')
            ->subject('Time for Symfony Mailer!')
            ->text('Sending emails is fun again!')
            ->html('<p>See Twig integration for better HTML integration!</p>');
        $this->mailer->send($email);
    }

}

SomeControllerTest.php

<?php

namespace App\Tests\Controller;

use App\Model\SomeActions;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class SomeControllerTest extends WebTestCase
{
    public function testSomeAction()
    {
        $client = static::createClient();

        // gets the special container that allows fetching private services
        $container = self::$container;


        $someActions = $this->getMockBuilder(SomeActions::class)
            ->disableOriginalConstructor()
            ->getMock();

        //expect that sendEmail will be called
        $someActions->expects($this->once())
            ->method('sendEmail');

        //overwrite the default service: class: Mock_SomeActions_e68f817a
        $container->set('App\Model\SomeActions', $someActions);


        $crawler = $client->request('GET', '/en/some/action');

        //submit the form
        $form = $crawler->selectButton('submit')->form();

        $client->submit($form);

        //after submit the default class injected in the controller is "App\Model\SomeActions" and not the mocked service
        $response = $client->getResponse();

        $this->assertResponseIsSuccessful($response);

    }
}

解决方法是禁用内核重启:

$client->disableReboot();

如果人们深入挖掘以了解引擎盖下发生的事情,这是有道理的。 我仍然不确定是否有更直接的答案。

public function testSomeAction()
{
    $client = static::createClient();
    $client->disableReboot();
...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM