首页 > 解决方案 > 在 symfony 4.4 的控制器中测试模拟服务

问题描述

我想在我的 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)了,我有很多依赖项需要其他依赖项并且它是不可维护的。或者我应该移动自定义日志并在其他服务中发送电子邮件并保持控制器没有这些依赖关系?

标签: phpsymfonytestingmockingsymfony4

解决方案


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

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

  1. config/services_test.yaml添加以下配置

    App\Service\MyService:
      public: true
    
  2. 模拟服务

    $myService = $this->createMock(MyService::class);
    $myService->expects($this->once())->method("getInfos")->willReturn([
        [
            'hi'=>'hi'
        ]
    ]);
    self::$container->set(MyService::class, $myService);
    
  3. 并发出 HTTP 请求

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

推荐阅读