测试验证错误的更好方法

Better way for testing validation errors

我正在测试一个表单,用户必须在其中引入一些介于 100 到 500 个字符之间的文本。

我用来模拟用户输入:

$this->actingAs($user)
->visit('myweb/create')
->type($this->faker->text(1000),'description')
->press('Save')
->see('greater than');

我在这里寻找响应中的 greater than 段文本...这取决于为该验证错误指定的翻译。

如何在不依赖于验证错误的文本并且仅依赖于错误本身的情况下进行相同的测试?

控制器:

public function store(Request $request)
{
    $success = doStuff($request);
    if ($success){
        Flash::success('Created');
    } else {
        Flash::error('Fail');
    }

    return Redirect::back():
}

dd(会话::所有()):

 `array:3 [
  "_token" => "ONoTlU2w7Ii2Npbr27dH5WSXolw6qpQncavQn72e"
  "_sf2_meta" => array:3 [
    "u" => 1453141086
    "c" => 1453141086
    "l" => "0"
  ]
  "flash" => array:2 [
    "old" => []
    "new" => []
  ]
]

你可以这样做 -

$this->assertSessionHas('flash_notification.level', 'danger'); 如果您正在寻找特定的错误或成功键。

或使用 $this->assertSessionHasErrors();

您的测试没有 post 调用。这是一个使用 Jeffery Way's flash package

的例子

控制器:

public function store(Request $request, Post $post)
{
    $post->fill($request->all());
    $post->user_id = $request->user()->id;

    $created = false;

    try {
        $created = $post->save();
    } catch (ValidationException $e) {
        flash()->error($e->getErrors()->all());
    }

    if ($created) {
        flash()->success('New post has been created.');
    }

    return back();
}

测试:

public function testStoreSuccess()
{
    $data = [
        'title' => 'A dog is fit',
        'status' => 'active',
        'excerpt' => 'Farm dog',
        'content' => 'blah blah blah',
    ];

    $this->call('POST', 'post', $data);

    $this->assertTrue(Post::where($data)->exists());
    $this->assertResponseStatus(302);
    $this->assertSessionHas('flash_notification.level', 'success');
    $this->assertSessionHas('flash_notification.message', 'New post has been created.');
}

从会话错误中获取 MessageBag 对象并使用 $errors->get('name')

获取所有验证错误名称
    $errors = session('errors');
    $this->assertSessionHasErrors();
    $this->assertEquals($errors->get('name')[0],"The title field is required.");

这适用于 Laravel 5 +

我认为有更明确的方法可以从会话中获取准确的错误消息。

    /** @var ViewErrorBag $errors */
    $errors = request()->session()->get('errors');
    /** @var array $messages */
    $messages = $errors->getBag('default')->getMessages();
    $emailErrorMessage = array_shift($messages['email']);

    $this->assertEquals('Already in use', $emailErrorMessage);

Pre-requirements: code was tested on Laravel Framework 5.5.14

尝试将您的测试分成多个单元,比如您测试控制器功能

您可能会捕获验证异常,如下所示:

} catch (ValidationException $ex) {

如果是手动生成的,应该是这样生成的:

throw ValidationException::withMessages([
            'abc' => ['my message'],
        ])->status(400);

你可以断言它喜欢

$this->assertSame('my message', $ex->errors()['abc'][0]);

如果你抓不住它,但更喜欢像这样测试路线:

    $response = $this->json('POST', route('user-post'), [
        'name'        => $faker->name,
        'email'       => $faker->email,            
    ]);

然后你使用 $response 断言验证已经发生,就像这样

$this->assertSame($response->errors->{'name'}[0], 'The name field is required.');

PS

在我使用的示例中

$faker = \Faker\Factory::create();

ValidationException 像这样使用

use Illuminate\Validation\ValidationException;

提醒您不​​必手动生成异常,常见情况使用validate方法:

$request->validate(['name' => [
            'required',
        ],
    ]);

我当前的 laravel 版本是 5.7