forms - Symfony 4 中 FormErrorSerializer 的单元测试 - 始终有效的形式
问题描述
我正在尝试为 FormErrorSerializer 编写一个单元测试,它将 Symfony $form->getErrors() 转换为可读数组。
我目前的方法是创建表单、为其提供数据并查找验证错误,但表单始终有效。无论我提供什么数据,我都不会收到任何错误。
在正常的 REST 请求/响应中,它运行良好,我收到了适当的错误消息。我需要帮助以获取单元测试中的错误消息。
namespace App\Tests\Unit;
use App\Form\UserType;
use App\Serializer\FormErrorSerializer;
use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\Translation\Translator;
class FormErrorSerializerTest extends TypeTestCase
{
/**
* ValidatorExtensionTrait needed for invalid_options
* https://github.com/symfony/symfony/issues/22593
*/
use ValidatorExtensionTrait;
public function testConvertFormToArray(){
$form_data = [
'email' => 'test',
'plainPassword' => [
'pass' => '1',
'pass2' => '2'
]
];
$translator = new Translator('de');
$form = $this->factory->create(UserType::class);
$form->submit($form_data);
if( $form->isValid() ) {
echo "Form is valid"; exit;
}
$formErrorSerializer = new FormErrorSerializer($translator);
$errors = $formErrorSerializer->convertFormToArray($form);
print_r($errors); exit;
}
}
在序列化器下方找到:
namespace App\Serializer;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Translation\TranslatorInterface;
/**
* Serializes invalid Form instances.
*/
class FormErrorSerializer
{
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function convertFormToArray(FormInterface $data)
{
$form = $errors = [];
foreach ($data->getErrors() as $error) {
$errors[] = $this->getErrorMessage($error);
}
if ($errors) {
$form['errors'] = $errors;
}
$children = [];
foreach ($data->all() as $child) {
if ($child instanceof FormInterface) {
$children[$child->getName()] = $this->convertFormToArray($child);
}
}
if ($children) {
$form['children'] = $children;
}
return $form;
}
private function getErrorMessage(FormError $error)
{
if (null !== $error->getMessagePluralization()) {
return $this->translator->transChoice(
$error->getMessageTemplate(),
$error->getMessagePluralization(),
$error->getMessageParameters(),
'validators'
);
}
return $this->translator->trans($error->getMessageTemplate(), $error->getMessageParameters(), 'validators');
}
}
解决方案
好的,我能够以两种不同的方式做到这一点。
第一个解决方案是在 getExtensions 方法中加载验证器。TypeTestCase 中的工厂不带验证器。因此,您不仅必须加载验证器,还必须明确指定验证。您可以使用 symfony 提供的方法指定验证,或者如果您正在使用验证器,则可以直接将验证器指向 YAML 或 xml 文件。
public function getExtensions()
{
$validator = (new ValidatorBuilder())
->addYamlMapping("path_to_validations.yaml")
->setConstraintValidatorFactory(new ConstraintValidatorFactory())
->getValidator();
$extensions[] = new CoreExtension();
$extensions[] = new ValidatorExtension($validator);
return $extensions;
}
但是,我没有使用上述方法。我选择了更好的解决方案。由于我的测试用例非常复杂(因为它需要多个服务),我使用了 Symfony 的 KernelTestCase 提供的特殊容器。它在测试中提供私有服务,并且它提供的工厂带有验证器和验证,就像您在控制器中编写代码一样。您不需要显式加载验证器。在下面找到我扩展 KernelTestCase 的最终测试。
namespace App\Tests\Unit\Serializer;
use App\Entity\User;
use App\Form\UserType;
use App\Serializer\FormErrorSerializer;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Translation\TranslatorInterface;
class FormErrorSerializerTest extends KernelTestCase
{
/**
* {@inheritDoc}
*/
protected function setUp()
{
$kernel = self::bootKernel();
}
public function testConvertFormToArray_invalidData(){
$form_data = [
'email' => 'test',
'plainPassword' => [
'pass' => '1111',
'pass2' => ''
]
];
$user = new User();
$user->setEmail($form_data['email']);
$user->setPlainPassword($form_data['plainPassword']['pass']);
$factory = self::$container->get(FormFactoryInterface::class);
/**
* @var FormInterface $form
*/
$form = $factory->create(UserType::class, $user);
$form->submit($form_data);
$this->assertTrue($form->isSubmitted());
$this->assertFalse($form->isValid());
$translator = self::$container->get(TranslatorInterface::class);
$formErrorSerializer = new FormErrorSerializer($translator);
$errors = $formErrorSerializer->convertFormToArray($form);
$this->assertArrayHasKey('errors', $errors['children']['email']);
$this->assertArrayHasKey('errors', $errors['children']['plainPassword']['children']['pass']);
}
public function testConvertFormToArray_validData(){
$form_data = [
'email' => 'test@example.com',
'plainPassword' => [
'pass' => 'somepassword@slkd12',
'pass2' => 'somepassword@slkd12'
]
];
$user = new User();
$user->setEmail($form_data['email']);
$user->setPlainPassword($form_data['plainPassword']['pass']);
$factory = self::$container->get(FormFactoryInterface::class);
/**
* @var FormInterface $form
*/
$form = $factory->create(UserType::class, $user);
$form->submit($form_data);
$this->assertTrue($form->isSubmitted());
$this->assertTrue($form->isValid());
$translator = self::$container->get(TranslatorInterface::class);
$formErrorSerializer = new FormErrorSerializer($translator);
$errors = $formErrorSerializer->convertFormToArray($form);
$this->assertArrayNotHasKey('errors', $errors['children']['email']);
$this->assertArrayNotHasKey('errors', $errors['children']['plainPassword']['children']['pass']);
}
}
请注意,Symfony 4.1 有一个特殊的容器,允许获取私有服务。
self::$kernel->getContainer();
不是特殊容器。它不会获取私人服务。
但是,self::$container;
是在测试中提供私有服务的特殊容器。
更多关于这里的信息。
推荐阅读
- python - Kivy:如何屏蔽所有用户交互?
- r - 如何使用 Plotly 在 R 中添加趋势线
- autodesk-forge - BIM360 Docs GET 文件夹内容页数限制
- python - 在 Django 中使用 jsonb_object_keys postgres 函数?
- amazon-web-services - AWS ElasticSearch - 自动化手动快照
- ios - 索引 16 越界;swift中的字符串长度为0
- spring-boot - Spring Boot:自动配置的工作原理和@JsonTest
- redirect - 限制 HTTP 引用者的请求 - IIS
- powerbi - Power BI-创建单选按钮筛选器(右侧窗格,不在仪表板/工作表上)
- view - ORACLE - 解码视图谓词并应用于基表