在 Symfony 4.4 中使用注解测试控制器

Posted

技术标签:

【中文标题】在 Symfony 4.4 中使用注解测试控制器【英文标题】:Testing Controllers in Symfony 4.4 while using annotations 【发布时间】:2020-09-03 21:43:41 【问题描述】:

我在使用 FOSRestBundle 和 JMSSserializer 在 Symfony 4.4 中测试我的控制器时遇到了问题。我的控制器非常简单,通常只包含对其他服务的调用,但我正在使用 ParamConverter、Serializer、Deserializer 等。我不确定返回的字段是否是我期望的。

我想测试序列化/反序列化如何处理我的实体。每当我在实体中添加字段或更改字段组时,测试都会失败。

理想情况下,我会模拟我的服务并直接调用 Action,但我在任何地方都找不到,如何调用所有注释触发的 Action 方法。

除了对整个请求进行功能测试之外,还有其他测试方法吗?

我要测试的控制器动作:

    /**
     * @Rest\Post("/entity")
     * @Rest\Put("/entity/entityId<\d+>?")
     * @ParamConverter(name="entity", converter="app.request_body",options=
     *         "deserializationContext"="groups"=
     *             "DetailsGroup",
     *             "nested"="IdGroup",
     *             "owner"="IdGroup"
     *         
     *     
     * )
     * @Rest\View(serializerGroups="IdGroup", statusCode=Response::HTTP_CREATED)
     * @param int|null $entityId
     * @param Entity $entity
     * @param ConstraintViolationListInterface $validationErrors
     * @return Entity
     * @throws InvalidArgumentException
     * @throws Exception
     */
    public function setEntityAction(?int $entityId, Entity $entity, ConstraintViolationListInterface $validationErrors): Entity
    
        if ($validationErrors->count() > 0) 
            throw new InvalidArgumentException('...');
        

        return $this->entityService->setEntity($entity, $this->getUser());
    

【问题讨论】:

到目前为止您尝试过什么?你被困在哪里了?为什么不编写一个期望给定输出的测试用例? 【参考方案1】:

当您想要考虑要覆盖的注释时,测试控制器通常需要进行大量设置。使用单元测试进行设置,您只需实例化控制器并模拟调用的服务是不够的。

您可以做的是使用 Symfony 的 WebTestCase 来运行通过启动的应用程序内核的功能测试。这几乎可以在一个设置中测试您的控制器,该设置非常类似于在您的应用程序中实际调用它时会发生的情况。这样做的缺点是,它还将运行所有服务。

您仍然可以尝试一些解决方法。您可以直接在正在使用的服务容器中替换控制器中调用的服务。通过更改测试中的容器或提供自定义config/services_test.yaml 将服务替换为“NullService”:

# config/services_test.yaml
services:
    App\Service\MyEntityService: # This is the original class name
        class: App\Service\NullService # This is the class name of the "null" service

这样,每当你注入MyEntityService,你都会得到NullService。这将要求您扩展原始服务或拥有一个它们都可以实现的接口。如果您有接口,您可能希望将其用作服务 ID,而不是原始类名。

这种方法的缺点是,您必须手动连接每个服务,并且必须为其创建一个虚拟替代品。好处是,您可以在控制实现时非常轻松地返回所需的数据。

另一种方法是更改​​测试本身的容器:

protected function testMyController(): void

    $kernel = self::bootKernel();

    $mock = $this->createMock(MyEntityService::class);

    $kernel->getContainer()->set(MyEntityService::class, $mock);

【讨论】:

以上是关于在 Symfony 4.4 中使用注解测试控制器的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

返回响应时,Symfony 4.4 转储不输出任何内容

返回响应时,Symfony 4.4 转储不输出任何内容

Symfony 4.4 Auth0 如何从应用程序中完全注销用户