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

Chr*_*phe 5 php forms functional-testing symfony domcrawler

当您通过浏览器使用该应用程序时,您发送了一个错误的值,系统会检查表单中的错误,如果出现问题(在本例中就是这样),它会重定向一条默认错误消息,该消息写在有罪的错误消息下方场地。

这是我试图用我的测试用例断言的行为,但我遇到了我没有预料到的 \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([]));
}
Run Code Online (Sandbox Code Playgroud)

这是我收到的异常消息:

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([]));
}
Run Code Online (Sandbox Code Playgroud)

这里测试的 ColorChoiceType 非常标准:

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
Run Code Online (Sandbox Code Playgroud)

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

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

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

Chr*_*phe 4

看来您可以禁用 DomCrawler\Form 组件上的验证。基于此处的官方文档。

所以这样做,现在可以按预期工作:

$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.
Run Code Online (Sandbox Code Playgroud)