如何使用 Symfony 爬虫组件和 PHPUnit 测试提交错误值的表单?

How to test form submission with wrong values using Symfony crawler component and PHPUnit?

当您通过浏览器使用该应用程序时,您发送了错误的值,系统会检查表单中的错误,如果出现问题(在本例中确实如此),它会重定向并显示默认错误信息写在有罪的字段下方。

这是我试图用我的测试用例断言的行为,但我遇到了一个我没有预料到的 \InvalidArgumentException。

我将 symfony/phpunit-bridge 与 phpunit/phpunit v8.5.23 和 symfony/dom-crawler v5.3.7 一起使用。 这是它的外观示例:

public function testPayloadNotRespectingFieldLimits(): void
{
    $client = static::createClient();

    /** @var SomeRepository $repo */
    $repo = self::getContainer()->get(SomeRepository::class);
    $countEntries = $repo->count([]);
    
    $crawler = $client->request(
        'GET',
        '/route/to/form/add'
    );
    $this->assertResponseIsSuccessful(); // Goes ok.

    $form = $crawler->filter('[type=submit]')->form(); // It does retrieve my form node.
    
    // This is where it's not working.
    $form->setValues([
        'some[name]' => 'Someokvalue',
        'some[color]' => 'SomeNOTOKValue', // It is a ChoiceType with limited values, where 'SomeNOTOKValue' does not belong. This is the line that throws an \InvalidArgumentException.
    )];

    // What I'd like to assert after this
    $client->submit($form);
    $this->assertResponseRedirects();
    $this->assertEquals($countEntries, $repo->count([]));
}

这是我收到的异常消息:

InvalidArgumentException: Input "some[color]" cannot take "SomeNOTOKValue" as a value (possible values: "red", "pink", "purple", "white").
vendor/symfony/dom-crawler/Field/ChoiceFormField.php:140
vendor/symfony/dom-crawler/FormFieldRegistry.php:113
vendor/symfony/dom-crawler/Form.php:75

这里测试的 ColorChoiceType 非常标准:

public function configureOptions(OptionsResolver $resolver): void
{
    $resolver->setDefaults([
        'choices' => ColorEnumType::getChoices(),
        'multiple' => false,
    )];
}

我能做的是将一个 try-catch 块包装起来,即设置错误值的行。它确实会提交表单并继续下一个断言。这里的问题是表单被认为 已提交且有效 ,它强制为颜色字段(枚举集的第一个选择)设置适当的值。 这 不是 我在浏览器中尝试此操作时得到的结果(参见简介)。

// ...
/** @var SomeRepository $repo */
$repo = self::getContainer()->get(SomeRepository::class);
$countEntries = $repo->count([]); // Gives 0.
// ...
try {
    $form->setValues([
        'some[name]' => 'Someokvalue',
        'some[color]' => 'SomeNOTOKValue',
    ]);
} catch (\InvalidArgumentException $e) {}

$client->submit($form); // Now it submits the form.
$this->assertResponseRedirects(); // Ok.
$this->assertEquals($countEntries, $repo->count([])); // Failed asserting that 1 matches expected 0. !!

如何在我的测试用例中模仿浏览器行为并对其进行断言?

您似乎可以在 DomCrawler\Form 组件上禁用验证。基于官方文档 here.

这样做,现在可以正常工作了:

$form = $crawler->filter('[type=submit]')->form()->disableValidation();
$form->setValues([
    'some[name]' => 'Someokvalue',
    'some[color]' => 'SomeNOTOKValue',
];
$client->submit($form);

$this->assertEquals($entriesBefore, $repo->count([]); // Now passes.