🕌
Laravel 作成したカスタムルールに対してテストを書いてみる
前書き
前回と前々回に作成したカスタムルールに対して、テストを書いてみたいと思います。
(フォームリクエストとかに対するものではなく)
最終形のカスタムルールは、下の方に掲載しておきます。
その1:前々回
その2:前回
本題
テストのファイルは以下のコマンドで作成します。
php artisan make:test Rules/AllRequiredRuleTest --unit
今回は、Laravel の世界を構築する必要は無くて済むので、--unit を付けています。(PHPUnit\Framework\TestCase を直接継承させます)
で、tests/Unit/Rules/AllRequiredRuleTest.php ファイルが生成されましたので、以下の感じで書いてやります。
<?php
namespace Tests\Unit\Rules;
use App\Rules\AllRequired;
use Illuminate\Translation\ArrayLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\Validator;
use PHPUnit\Framework\TestCase;
class AllRequiredRuleTest extends TestCase
{
/** @test */
function AllRequired、全て埋まってないのでvalidationエラー()
{
$trans = $this->getTranslator();
$rules = ['foo1' => new AllRequired('foo2', 'foo3')];
$this->fails(new Validator($trans, [], $rules));
$this->fails(new Validator($trans, ['foo1' => 'ほげ'], $rules));
$this->fails(new Validator($trans, ['foo1' => 'ほげ', 'foo2' => null], $rules));
$this->fails(new Validator($trans, ['foo1' => 'ばー', 'foo2' => 'ばず'], $rules));
$this->fails(new Validator($trans, ['foo2' => 'ばー'], $rules));
$this->fails(new Validator($trans, ['foo3' => 'ばず'], $rules));
$this->fails(new Validator($trans, ['foo2' => 'ばー', 'foo3' => 'ばず'], $rules));
$rules = ['foo1' => new AllRequired(['foo2', 'foo3'])]; // 配列で指定
$this->fails(new Validator($trans, ['foo1' => 'ばー', 'foo2' => 'ばず'], $rules));
}
/** @test */
function AllRequired、全て埋まっているのでvalidation、OK()
{
$trans = $this->getTranslator();
$rules = ['foo1' => new AllRequired('foo2', 'foo3')];
$this->passes(new Validator($trans, ['foo1' => 'ほげ', 'foo2' => 'ばー', 'foo3' => 'ばず'], $rules));
$rules = ['foo1' => new AllRequired(['foo2', 'foo3'])]; // 配列で指定
$this->passes(new Validator($trans, ['foo1' => 'ほげ', 'foo2' => 'ばー', 'foo3' => 'ばず'], $rules));
}
/** @test */
function AllRequired、デフォルトのエラーメッセージがセットされる()
{
$trans = $this->getTranslator();
$rules = ['foo1' => new AllRequired('foo2')];
$this->assertSame(
['foo1' => ['foo1を入力してください。']],
(new Validator($trans, [], $rules))->messages()->toArray()
);
}
/** @test */
function AllRequired、setMessageでエラーメッセージがセットされる()
{
$trans = $this->getTranslator();
$rules = ['foo1' => (new AllRequired('foo2'))->setMessage('全て必須です。')];
$this->assertSame(
['foo1' => ['全て必須です。']],
(new Validator($trans, [], $rules))->messages()->toArray()
);
}
/** @test */
function AllRequired、skipIfのテスト()
{
$trans = $this->getTranslator();
$rules = ['foo1' => (new AllRequired('foo2'))->skipIf(true)];
$this->passes(new Validator($trans, [], $rules));
$rules = ['foo1' => (new AllRequired('foo2'))->skipIf(fn () => true)];
$this->passes(new Validator($trans, [], $rules));
$rules = ['foo1' => (new AllRequired('foo2'))->skipIf(false)];
$this->fails(new Validator($trans, [], $rules));
$rules = ['foo1' => (new AllRequired('foo2'))->skipIf(fn () => false)];
$this->fails(new Validator($trans, [], $rules));
}
protected function fails($validator)
{
$this->assertFalse($validator->passes());
}
protected function passes($validator)
{
$this->assertTrue($validator->passes());
}
protected function getTranslator()
{
return new Translator(
new ArrayLoader, 'en'
);
}
}
大体、ご覧いただいた通りです🙇♂️。一部、Laravel本体のソースなども参考にしております。
テスト対象のカスタムルールは下記です。
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ImplicitRule;
class AllRequired implements ImplicitRule, DataAwareRule
{
public bool $skip = false;
protected array $others = [];
protected string $message = ":attributeを入力してください。";
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct($others)
{
$this->others = is_array($others) ? $others : func_get_args();
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
if ($this->skip) {
return true;
}
$fields = array_merge([$attribute], $this->others);
foreach($fields as $field) {
if (! isset($this->data[$field]) || blank($this->data[$field])) {
return false;
}
}
return true;
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return $this->message;
}
/**
* エラーメッセージを設定する
*
* @param string $message
* @return object $this
*/
public function setMessage($message)
{
$this->message = $message;
return $this;
}
/**
* Set the data under validation.
*
* @param array $data
* @return $this
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
/**
* $callback が true の時は、validationを走らせない
*
* @param mixed $callback
* @return object $this
*/
public function skipIf($callback)
{
$this->skip = !! value($callback);
return $this;
}
}
雑感
3回の連続ものにすると、「もう読んでくれている方もいないのではないか…」と思ったりしますが😅、めげずに書いてみました。
おかしな箇所等ありましたら、コメント下さい。
Discussion