在 symfony 4.4 的控制器中测试模拟服务

Posted

技术标签:

【中文标题】在 symfony 4.4 的控制器中测试模拟服务【英文标题】:Test mocked service in controller in symfony 4.4 【发布时间】:2021-12-23 02:49:36 【问题描述】:

我想在我的 symfony 4.4 项目中测试这个控制器:

final class WebhookController extends AbstractController

    private CustomLoggerService $customLogger;
    private EntityManagerInterface $entityManager;
    private MyService $myService;
    private UserMailer $userMailer;
    private AdminMailer $adminMailer;

    public function __construct
    (
        CustomLoggerService $customLogger,
        EntityManagerInterface $entityManager,
        MyService $myService,
        UserMailer $userMailer,
        AdminMailer $adminMailer
    )
    
        $this->customLogger = $customLogger;
        $this->myService = $myService;
        $this->userMailer = $userMailer;
        $this->adminMailer = $adminMailer;
        $this->entityManager = $entityManager;
    

    /**
     * @Route("/webhook/new", name="webhook_new")
     * @param Request $request
     * @return Response
     */
    public function new(Request $request)
    
        $uri = $request->getUri();
        $this->customLogger->info("new event uri ".$uri);
        $query = $request->query->all();
        if(isset($query['RessourceId']))
        
            //infos
            $id = $query['RessourceId'];
            $event = $this->myService->getInfos($id);
            $infoId = $event->infoId;
            $this->customLogger->info("new info id ".$infoId);

            $userRepo = $this->entityManager->getRepository(User::class);
            $user = $userRepo->findOneByEventUserId((int)$event->owners[0]);

            //mail sent
            $this->userMailer->sendAdminEvent($event, $user);
            $this->customLogger->info("new mail sent");

        
        else
        
            $this->adminMailer->sendSimpleMessageToAdmin("no ressource id", "no ressource id");
        
        return new JsonResponse();
    

我需要模拟 MyService,因为它调用外部 API

这是我的测试:

class WebhookControllerTest extends WebTestCase

    use LoginTrait;

    public function testNewPayinIRessourceIdExists()
    
        self::ensureKernelShutdown();
        /** @var KernelBrowser $client */
        $client = $this->startClient();
        $client->enableProfiler();

        $myService = $this->createMock(MyService::class);
        $myService->expects($this->once())->method("getInfos")->willReturn([
            [
                'hi'=>'hi'
            ]
        ]);


        // if I do this, I can't inject my mocked service
        $client->request('GET', '/webhook/new/?RessourceId=1111');
        
       // if I do this, I can't autowire all my dependencies of my controller
       $controller = new WebhookController(xxxx);
       $controller->new(xxx);
    

测试我的控制器的最佳方法是什么?如果我这样做 new WebhookController(xxxx) 我有很多依赖项需要其他依赖项并且它是不可维护的。 或者我应该移动自定义日志并在其他服务中发送电子邮件并保持控制器没有这些依赖关系?

【问题讨论】:

【参考方案1】:

你不需要自己实例化控制器。

您可以将需要模拟的服务公开用于测试环境,在容器中创建模拟和覆盖。

    config/services_test.yaml添加以下配置

    App\Service\MyService:
      public: true
    

    模拟服务

    $myService = $this->createMock(MyService::class);
    $myService->expects($this->once())->method("getInfos")->willReturn([
        [
            'hi'=>'hi'
        ]
    ]);
    self::$container->set(MyService::class, $myService);
    

    并发出 HTTP 请求

    $client->request('GET', '/webhook/new/?RessourceId=1111');
    

【讨论】:

谢谢@greeflas 我不知道这个:) 我试过了,但我不能做我想做的事。当我使用这种技术时,$myService->getInfos(1111) 在我的测试中返回我的正确对象,但在测试中,我测试的控制器仍然想要使用 API 并尝试连接它并使用真实方法而不是我的模拟。似乎模拟没有传递给控制器​​。你明白为什么吗?非常感谢:) 我改的,不知道加参数是不是问题services: App\Service\MyService: arguments: $myParameters: '%my_parameters%' public: true 你能试试static::$kernel->getContainer()->set(MyService::class, $myService)吗?它应该与控制器内部的容器相同。 我试过 $client->getContainer()->set(MyService::class, $myService);self::$container->set(MyService::class, $myService);static::$kernel->getContainer()->set(MyService::class, $myService) 他们都没有工作:/ 哇非常感谢!!!你的例子在我的环境中工作所以......我不知道为什么我有这个问题。我会继续我的调查谢谢:)

以上是关于在 symfony 4.4 的控制器中测试模拟服务的主要内容,如果未能解决你的问题,请参考以下文章

Symfony:在功能测试中模拟 LDAP 组件

Symfony 4.4控制器容器事件分派器

我啥时候应该在 Symfony 4.4 控制器中使用拒绝访问功能?

用户测试中多个客户端的 Symfony 4.4 弃用警告已弃用,但仍存在于文档中

Symfony 3模拟服务功能测试phpunit和liip

在 Symfony 4.4 中实现自定义错误控制器