如何使用约束属性对 symfony dto 进行单元测试

问题描述 投票:0回答:1

我有一个新创建的 Symfony 7 应用程序,并且有一个名为:AuthCallbackDto 的 DTO

<?php

declare(strict_types=1);

namespace App\Application\Model\Auth;

use Symfony\Component\Validator\Constraints as Assert;

readonly class AuthCallbackDto
{
    public function __construct(
        #[Assert\NotBlank(message: 'The `code` value cannot be blank')]
        #[Assert\Length(min: 5)]
        private string $code,
        #[Assert\NotBlank(message: 'The `session_state` value cannot be blank')]
        #[Assert\Length(min: 5)]
        private string $session_state,
    ) {
    }

    public function getCode(): string
    {
        return $this->code;
    }

    public function getSessionState(): string
    {
        return $this->session_state;
    }
}

我在控制器中使用它,如下所示:

<?php

declare(strict_types=1);

namespace App\Application\Controller\Auth;

use App\Application\Model\Auth\AuthCallbackDto;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Attribute\MapQueryString;
use Symfony\Component\Routing\Attribute\Route;

#[AsController]
class Callback
{
    #[Route('/auth/callback', name: 'auth/callback', methods: ['GET'])]
    public function test(
        #[MapQueryString] AuthCallbackDto $authCallbackDto,
    ): Response {

        return new JsonResponse([
            'code' => $authCallbackDto->getCode(),
            'session_state' => $authCallbackDto->getSessionState()
        ]);
    }
}

如果代码或 session_state 值不存在或 < 5 characters then an error is thrown. This is good!

http://localhost:8000/auth/callback?code=oihiohoih&session_state=34f34f34f - 有效(好) http://localhost:8000/auth/callback?code=&session_state= - 失败(好) 'http://localhost:8000/auth/callback?code=123&session_state=123 - 失败(好)

由于过于自信,我决定为 DTO 类编写一个非常小的单元测试。然而,我随后注意到当我从控制台运行 PHP Unit 时,约束属性没有被应用。测试中的异常永远不会抛出。

任何人都可以告诉我我做错了什么还是我只是假设太多?

这是我的单元测试:

<?php

declare(strict_types=1);

namespace App\Tests\Unit\Application\Model\Auh;

use App\Application\Model\Auth\AuthCallbackDto;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

class AuhCallbackDtoTest extends TestCase
{
    /**
     * @return array<array<int, string|bool>>
     */
    public static function dtoData(): array
    {
        return [
            [
                '',
                '',
                true,
            ],
            [
                'someCodeABC12344',
                'someSessionState',
                false,
            ],
        ];
    }

    #[DataProvider('dtoData')]
    public function testDtoCanBeCreated(string $code, string $sessionState, bool $exception): void
    {
        if ($exception) {
            $this->expectException(\Exception::class);
        }

        $dto = new AuthCallbackDto($code, $sessionState);

        self::assertEquals($dto->getCode(), $code);
        self::assertEquals($dto->getSessionState(), $sessionState);
    }
}

我尝试使用控制台调试验证规则,看起来不错:


bin/console debug:validator 'App\Application\Model\Auth\AuthCallbackDto'


App\Application\Model\Auth\AuthCallbackDto
------------------------------------------

+---------------+--------------------------------------------------+--------------------------+---------------------------------------------------------------------------------+
| Property      | Name                                             | Groups                   | Options                                                                         |
+---------------+--------------------------------------------------+--------------------------+---------------------------------------------------------------------------------+
| code          | property options                                 |                          | [                                                                               |
|               |                                                  |                          |   "cascadeStrategy" =>                                                          |
|               |                                                  |                          | "None",                                                                         |
|               |                                                  |                          |   "autoMappingStrategy" =>                                                      |
|               |                                                  |                          | "None",                                                                         |
|               |                                                  |                          |   "traversalStrategy" =>                                                        |
|               |                                                  |                          | "None"                                                                          |
|               |                                                  |                          | ]                                                                               |
| code          | Symfony\Component\Validator\Constraints\NotBlank | Default, AuthCallbackDto | [                                                                               |
|               |                                                  |                          |   "allowNull" =>                                                                |
|               |                                                  |                          | false,                                                                          |
|               |                                                  |                          |   "message" => "The `code`                                                      |
|               |                                                  |                          | value cannot be blank",                                                         |
|               |                                                  |                          |   "normalizer" =>                                                               |
|               |                                                  |                          | null,                                                                           |
|               |                                                  |                          |   "payload" =>                                                                  |
|               |                                                  |                          | null                                                                            |
|               |                                                  |                          | ]                                                                               |
| code          | Symfony\Component\Validator\Constraints\Length   | Default, AuthCallbackDto | [                                                                               |
|               |                                                  |                          |   "charset" =>                                                                  |
|               |                                                  |                          | "UTF-8",                                                                        |
|               |                                                  |                          |   "charsetMessage" => "This                                                     |
|               |                                                  |                          | value does not match the expected {{ charset }} charset.",                      |
|               |                                                  |                          |   "countUnit" =>                                                                |
|               |                                                  |                          | "codepoints",                                                                   |
|               |                                                  |                          |   "exactMessage" => "This                                                       |
|               |                                                  |                          | value should have exactly {{ limit }} character.|This value should have exactly |
|               |                                                  |                          | {{ limit }} characters.",                                                       |
|               |                                                  |                          |   "max" =>                                                                      |
|               |                                                  |                          | null,                                                                           |
|               |                                                  |                          |   "maxMessage" => "This value                                                   |
|               |                                                  |                          | is too long. It should have {{ limit }} character or less.|This value is too    |
|               |                                                  |                          | long. It should have {{ limit }} characters or less.",                          |
|               |                                                  |                          |   "min" => 5,                                                                   |
|               |                                                  |                          |   "minMessage" => "This value                                                   |
|               |                                                  |                          | is too short. It should have {{ limit }} character or more.|This value is too   |
|               |                                                  |                          | short. It should have {{ limit }} characters or more.",                         |
|               |                                                  |                          |   "normalizer" =>                                                               |
|               |                                                  |                          | null,                                                                           |
|               |                                                  |                          |   "payload" =>                                                                  |
|               |                                                  |                          | null                                                                            |
|               |                                                  |                          | ]                                                                               |
| session_state | property options                                 |                          | [                                                                               |
|               |                                                  |                          |   "cascadeStrategy" =>                                                          |
|               |                                                  |                          | "None",                                                                         |
|               |                                                  |                          |   "autoMappingStrategy" =>                                                      |
|               |                                                  |                          | "None",                                                                         |
|               |                                                  |                          |   "traversalStrategy" =>                                                        |
|               |                                                  |                          | "None"                                                                          |
|               |                                                  |                          | ]                                                                               |
| session_state | Symfony\Component\Validator\Constraints\NotBlank | Default, AuthCallbackDto | [                                                                               |
|               |                                                  |                          |   "allowNull" =>                                                                |
|               |                                                  |                          | false,                                                                          |
|               |                                                  |                          |   "message" => "The                                                             |
|               |                                                  |                          | `session_state` value cannot be blank",                                         |
|               |                                                  |                          |   "normalizer" =>                                                               |
|               |                                                  |                          | null,                                                                           |
|               |                                                  |                          |   "payload" =>                                                                  |
|               |                                                  |                          | null                                                                            |
|               |                                                  |                          | ]                                                                               |
| session_state | Symfony\Component\Validator\Constraints\Length   | Default, AuthCallbackDto | [                                                                               |
|               |                                                  |                          |   "charset" =>                                                                  |
|               |                                                  |                          | "UTF-8",                                                                        |
|               |                                                  |                          |   "charsetMessage" => "This                                                     |
|               |                                                  |                          | value does not match the expected {{ charset }} charset.",                      |
|               |                                                  |                          |   "countUnit" =>                                                                |
|               |                                                  |                          | "codepoints",                                                                   |
|               |                                                  |                          |   "exactMessage" => "This                                                       |
|               |                                                  |                          | value should have exactly {{ limit }} character.|This value should have exactly |
|               |                                                  |                          | {{ limit }} characters.",                                                       |
|               |                                                  |                          |   "max" =>                                                                      |
|               |                                                  |                          | null,                                                                           |
|               |                                                  |                          |   "maxMessage" => "This value                                                   |
|               |                                                  |                          | is too long. It should have {{ limit }} character or less.|This value is too    |
|               |                                                  |                          | long. It should have {{ limit }} characters or less.",                          |
|               |                                                  |                          |   "min" => 5,                                                                   |
|               |                                                  |                          |   "minMessage" => "This value                                                   |
|               |                                                  |                          | is too short. It should have {{ limit }} character or more.|This value is too   |
|               |                                                  |                          | short. It should have {{ limit }} characters or more.",                         |
|               |                                                  |                          |   "normalizer" =>                                                               |
|               |                                                  |                          | null,                                                                           |
|               |                                                  |                          |   "payload" =>                                                                  |
|               |                                                  |                          | null                                                                            |
|               |                                                  |                          | ]                                                                               |
+---------------+--------------------------------------------------+--------------------------+---------------------------------------------------------------------------------+

我可以更新 DTO 的构造函数以进行一些标准的 Webmozart 静态断言调用,但当应用程序按预期运行时,这是不必要的。

...
 public function __construct(
        #[Assert\NotBlank]
        #[Assert\Length(min: 5)]
        private string $code,
        #[Assert\NotBlank]
        #[Assert\Length(min: 5)]
        private string $session_state,
    ) {
        \Webmozart\Assert\Assert::notEmpty($this->code);
        \Webmozart\Assert\Assert::minLength($code, 5);

        \Webmozart\Assert\Assert::notEmpty($this->session_state);
        \Webmozart\Assert\Assert::minLength($this->session_state, 5);
    }
...
php symfony phpunit
1个回答
0
投票

那些

Assert
属性来自 Symfony Validator 组件。 PHP 不会自动在其上运行业务逻辑。但它确实在框架中做到了这一点。

您需要将其传递给 symfony 验证器。

但是,由于您正在测试控制器,因此您可以创建一个

WebTestCase
来代替。您可以通过发送请求并验证响应来(功能上)测试您的控制器。简而言之,就像您的应用程序是一个“黑匣子”一样运行功能测试。

有关更多信息,请参阅本章:https://symfony.com/doc/current/testing.html#write-your-first-application-test

如果你真的不想要这个,并且你真的想测试你的 Dto。您必须使用 Symfony 验证器验证您的 Dto。

class AuhCallbackDtoTest extends TestCase
{

    public function testInvalidDto(): void
    {
        $validator = Validation::createValidator();

        $dto = new AuthCallbackDto("", "");

        $errors = $validator->validate($dto);
        
        $this->assertCount(2, (array)$errors);  // there are 2 errors
        // You can check specifically for the error and the error message too
    }
}
仅供参考,我还没有真正测试过这一点。因此

Validation::createValidator()

 可能需要一些额外的配置来理解这些构造函数属性,但我并不完全确定。

© www.soinside.com 2019 - 2024. All rights reserved.