首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >PHPUnit Symfony4创建和测试自定义验证器

PHPUnit Symfony4创建和测试自定义验证器
EN

Stack Overflow用户
提问于 2018-07-05 02:36:21
回答 1查看 1.1K关注 0票数 1

我的目标是构建自定义验证器并使用PHPUnit对其进行测试。

PasswordComplexity.php

代码语言:javascript
复制
<?php

namespace App\Components\Validator\Constraint;

use Symfony\Component\Validator\Constraints\Regex;

/**
 * Class Password
 * @package App\Components\Validator\Constraint
 * @Annotation
 */
class PasswordComplexity extends Regex
{
    public $message = 'The password "{{string}}" does not meet the password policy requirements.';
    public $pattern = [
        '/.{8,}/',
        '/\d+/',
        '/[a-z]+/',
        '/[A-Z]+/',
        '/[!@#$%\-_*+=]+/'
    ];

    /**
     * {@inheritdoc}
     */
    public function getRequiredOptions()
    {
        return [];
    }
}

PasswordComplexityValidator.php

代码语言:javascript
复制
<?php
declare(strict_types=1);
namespace App\Components\Validator\Constraint;

use Symfony\Component\Validator\Constraints\RegexValidator;

class PasswordComplexityValidator extends RegexValidator
{
}

PasswordComplexityValidatorTest.php

代码语言:javascript
复制
<?php
declare(strict_types=1);
namespace App\Tests\Components\Validator\Constraint;

use App\Components\Validator\Constraint\PasswordComplexity;
use App\Components\Validator\Constraint\PasswordComplexityValidator;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Context\ExecutionContext;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;

class PasswordComplexityValidatorTest extends TestCase
{
    public function testRequiredOptions()
    {
        $validator = new PasswordComplexity();
        $this->assertEquals([], $validator->getRequiredOptions());
    }

    /**
     * @dataProvider validPasswordProvider
     */
    public function testValidation($value)
    {
        $constraint = new PasswordComplexity();

        /** @var ExecutionContextInterface|MockObject $context */
        $context = $this->getMockExecutionContext();
        $context->expects($this->never())->method('buildViolation');

        $validator = new PasswordComplexityValidator();
        $validator->initialize($context);

        $validator->validate($value, $constraint);
    }

    /**
     * @dataProvider invalidPasswordProvider
     */
    public function testValidationFail($value)
    {
        $constraint = new PasswordComplexity();

        /** @var ExecutionContextInterface|MockObject $context */
        $context = $this->getMockExecutionContext();
        $context->expects($this->once())
            ->method('buildViolation')
            ->with($constraint->message)
            ->willReturn($this->getMockConstraintViolationBuilder());

        $validator = new PasswordComplexityValidator();
        $validator->initialize($context);
        $validator->validate($value, $constraint);
    }

    public function validPasswordProvider()
    {
        return [
            ['jXb8p$cn'],
            ['!MC6NcuS'],
            ['!3%Sy6iF'],
            ['XyiWmw2#'],
            ['r@5e#hSY'],
        ];
    }

    public function invalidPasswordProvider()
    {
        return [                // conditions not meet:
            ['YQ(GJ)&'],        // at least 8 characters
            ['LuAqA=uX'],       // at least 1 digit (0 to 9)
            ['{OG>:@I1'],       // at least 1 small case letter
            [']su-(+\a'],       // at least 1 upper case letter
            ['CJuCyAGc'],       // at least 1 special character
        ];
    }

    private function getMockExecutionContext()
    {
        $context = $this->getMockBuilder(ExecutionContext::class)
            ->disableOriginalConstructor()
            ->getMock();
        return $context;
    }

    private function getMockConstraintViolationBuilder()
    {
        $constraintViolationBuilder = $this->getMockBuilder(ConstraintViolationBuilderInterface::class)->getMock();
        $constraintViolationBuilder
            ->method('setParameter')
            ->willReturn($constraintViolationBuilder);
        $constraintViolationBuilder
            ->method('setCode')
            ->willReturn($constraintViolationBuilder);
        $constraintViolationBuilder
            ->method('addViolation');
        return $constraintViolationBuilder;
    }

我有如下错误:

下面是10个错误:

具有数据集#0 ('jXb8p$cn')的

\Tests\Components\Validator\Constraint\PasswordComplexityValidatorTest::testValidation preg_match()要求参数1是字符串,给定的数组

我不知道如何将数组样本传递给验证器。

EN

回答 1

Stack Overflow用户

发布于 2018-07-05 03:33:35

我已经解决了这个问题。

我的正则表达式模式与样本数据不匹配,更改为:

代码语言:javascript
复制
public function invalidPasswordProvider()
{
    return [                // conditions not meet:
        ['J#$j#2'],        // at least 8 characters
        ['LuAqA=uX'],       // at least 1 digit (0 to 9)
        ['$OG3W4I1'],       // at least 1 small case letter
        ['3su-a+aa'],       // at least 1 upper case letter
        ['CJuC$AGc'],       // at least 1 special character
    ];
}

从PasswordComplexity.php中删除模式变量

代码语言:javascript
复制
public $pattern = [
    '/.{8,}/',
    '/\d+/',
    '/[a-z]+/',
    '/[A-Z]+/',
    '/[!@#$%\-_*+=]+/'
];

PasswordComplexityValidator.php中已填充了验证函数和所有必需的数据:

代码语言:javascript
复制
<?php
declare(strict_types=1);
namespace App\Components\Validator\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\RegexValidator;

class PasswordComplexityValidator extends RegexValidator
{
    const PASS_REQ_1 = '/.{8,}/';           // at least 8 characters
    const PASS_REQ_2 = '/\d+/';             // at least 1 digit (0 to 9)
    const PASS_REQ_3 = '/[a-z]+/';          // at least 1 small case letter
    const PASS_REQ_4 = '/[A-Z]+/';          //  at least 1 upper case letter
    const PASS_REQ_5 = '/[!@#$%\-_*+=]+/';  //  at least 1 special character (e.g.: !@#$%-_*+=)

    public static $patterns = [
        self::PASS_REQ_1,
        self::PASS_REQ_2,
        self::PASS_REQ_3,
        self::PASS_REQ_4,
        self::PASS_REQ_5,
    ];

    public function validate($password, Constraint $constraint)
    {
        foreach (self::$patterns as $pattern) {
            if (!preg_match($pattern, $password, $matches))
            {
                $this->context
                    ->buildViolation($constraint->message)
                    ->setParameter('{{ string }}', $password)
                    ->addViolation();
            }
        }
    }
}

也改变了

代码语言:javascript
复制
/**
 * @dataProvider invalidPasswordProvider
 */
public function testValidationFail($value)
{
    $constraint = new PasswordComplexity();

    /** @var ExecutionContextInterface|MockObject $context */
    $context = $this->getMockExecutionContext();
    $context->expects($this->once())

代码语言:javascript
复制
$context->expects($this->atLeast(1))

如果不匹配多个正则表达式,则测试密码。

测试通过了,我觉得现在一切都应该是这样的。

致敬,J

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51179377

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档