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

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

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

您可以为测试环境创建需要模拟的服务 public,在容器中创建模拟和覆盖。

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