高階テスト

「高階テスト」は複雑な用語に見えるかもしれませんが、実際にはテストを簡素化する手法であり、完全にオプションです。Pestの中核となる理念の1つは、ソースコードと同様に、テストスイートの美しさとシンプルさを重視することをユーザーに奨励することです。そのため、この手法に興味を持ち、コードの特定の部分で採用することを選択するかもしれません。

既存のテストを高階テストに移行する方法を示す例を考えてみましょう。説明のために、簡単なテストを使用します。

1it('works', function () {
2 $this->get('/')
3 ->assertStatus(200);
4});

この例に基づくと、テストのコンテンツ全体が`$this`変数に対して行われた連鎖呼び出しであることがわかります。このような場合、テストクロージャ全体を削除し、必要なメソッドを`it()`関数に直接連鎖させることができます。

1it('works')
2 ->get('/')
3 ->assertStatus(200);

クロージャ関数を削除し、テスト本体のメソッドを`test()`または`it()`関数に直接連鎖させる手法は、一般に「高階テスト」と呼ばれます。このアプローチは、テストスイートのコードを大幅に簡素化できます。

この手法は、期待値APIと組み合わせることもできます。ユーザーが正しい名前で作成されたことを確認するために期待値APIを使用するテストを見てみましょう。

1it('has a name', function () {
2 $user = User::create([
3 'name' => 'Nuno Maduro',
4 ]);
5 
6 expect($user->name)->toBe('Nuno Maduro');
7});

テストに期待値が1つだけ含まれている場合は、高階テストを使用して簡素化できます。

1it('has a name')
2 ->expect(fn () => User::create(['name' => 'Nuno Maduro'])->name)
3 ->toBe('Nuno Maduro');

クロージャを`expect()`メソッドに渡すことにより、期待値の遅延評価を使用することが重要です。これにより、期待値はテストの実行時にのみ作成され、それ以前には作成されないことが保証されます。

実行時に遅延評価が必要なオブジェクトに対してアサーションを行う必要がある場合は、`defer()`メソッドを使用できます。

1it('creates admins')
2 ->defer(fn () => $this->artisan('user:create --admin'))
3 ->assertDatabaseHas('users', ['id' => 1]);

上記の例では、`assertDatabaseHas()`アサーションメソッドは、`defer()`メソッドに渡されたクロージャの結果に対して呼び出されます。

高階テストの原則は、フックにも適用できます。つまり、フックの本体が`$this`変数に連鎖された一連のメソッドで構成されている場合、これらのメソッドをフックメソッドに連鎖させ、クロージャを完全に省略することができます。

1beforeEach(function () {
2 $this->withoutMiddleware();
3});
4 
5// Can be rewritten as...
6beforeEach()->withoutMiddleware();

高階テストを使用する場合、データセットの値は便宜上`expect()`および`defer()`クロージャに渡されます。

1it('validates emails')
2 ->with(['taylor@laravel.com', 'enunomaduro@gmail.com'])
3 ->expect(fn (string $email) => Validator::isValid($email))
4 ->toBeTrue();

高階期待値

高階期待値を使用すると、期待値`$value`の`プロパティ`または`メソッド`に対して直接期待値を実行できます。

たとえば、ユーザーが正常に作成され、さまざまな属性がデータベースに保存されていることをテストしているとします。テストは次のようになります。

1expect($user->name)->toBe('Nuno');
2expect($user->surname)->toBe('Maduro');
3expect($user->addTitle('Mr.'))->toBe('Mr. Nuno Maduro');

高階期待値を利用するには、プロパティとメソッドを`expect()`関数に直接連鎖させるだけで、Pestはテスト中の`$value`のプロパティ値の取得またはメソッドの呼び出しを処理します。

それでは、同じテストを高階期待値にリファクタリングした例を見てみましょう。

1expect($user)
2 ->name->toBe('Nuno')
3 ->surname->toBe('Maduro')
4 ->addTitle('Mr.')->toBe('Mr. Nuno Maduro');

配列を操作する場合、`$value`配列キーにアクセスして、それらに期待値を実行することもできます。

1expect(['name' => 'Nuno', 'projects' => ['Pest', 'OpenAI', 'Laravel Zero']])
2 ->name->toBe('Nuno')
3 ->projects->toHaveCount(3)
4 ->each->toBeString();
5 
6expect(['Dan', 'Luke', 'Nuno'])
7 ->{0}->toBe('Dan');

高階期待値は、すべての期待値で使用でき、クロージャ内でさらに高階期待値を作成することもできます。

1expect(['name' => 'Nuno', 'projects' => ['Pest', 'OpenAI', 'Laravel Zero']])
2 ->name->toBe('Nuno')
3 ->projects->toHaveCount(3)
4 ->sequence(
5 fn ($project) => $project->toBe('Pest'),
6 fn ($project) => $project->toBe('OpenAI'),
7 fn ($project) => $project->toBe('Laravel Zero'),
8 );

スコープ付き高階期待値

スコープ付き高階期待値を使用すると、メソッド`scoped()`とクロージャを使用して、チェーン内の特定のレベルに期待値へのアクセスとロックを行うことができます。

これは、子リレーションのプロパティを確認したいLaravel Eloquentモデルに非常に役立ちます。

1expect($user)
2->name->toBe('Nuno')
3->email->toBe('enunomaduro@gmail.com')
4->address()->scoped(fn ($address) => $address
5 ->line1->toBe('1 Pest Street')
6 ->city->toBe('Lisbon')
7 ->country->toBe('Portugal')
8);

高階テストは複雑に見えるかもしれませんが、テストスイートのコードを大幅に簡素化できる手法です。次のセクションでは、Pestのコミュニティビデオリソースについて説明します:ビデオリソース