0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel / PHPUnit】なぜClosureはUnitテストでモックできないのか?

0
Posted at

解決したいエラー

public function validate(string $type_name, mixed $input_value, Closure $error): void
{
    if (...) {
        $error('エラーメッセージ');
    }
}

上記コードのUnitテストを書く際に、
$fail を Mockery でモックすると以下のようなエラーになる。

The class \Closure is marked final and its methods cannot be replaced.

結論

Closureは final クラスだから、通常の方法ではモックできない。

なぜモックできないのか?

① ClosureはPHPの内部クラス

・final が付いている
・継承できない
・メソッドを差し替えできない

final class Closure

② Mockeryの仕組み

Mockeryは基本的に:
「元のクラスを継承して、メソッドを上書きする」
ことでモックを作ります。

しかし、final クラスは継承できません。

そのため以下のモックは失敗します。

Mockery::mock(Closure::class);

ではどうテストするのか?

Closureをモックするのではなく、

コールバックの副作用を検証する

のが正解です。

例:フラグで検証する方法

・$fail が呼ばれたらフラグを立てる
・フラグをアサートする

$error_called = false;

$error = function ($message) use (&$error_called) {
    $error_called = true;
};

$xxx->validate('name属性', 'input値', $fail);

$this->assertTrue($error_called);

Unitテストの観点

Unitテストは
「ロジックが正しく分岐したか」
を確認するもの。

Closureは分岐結果を外に伝えるための仕組みなので、
・呼ばれたかどうか
・渡された値が正しいか
を検証すれば十分。

項目 結論
Closureはモックできる? 通常はできない
理由 finalクラスだから
正しいテスト方法 副作用(フラグ・値)を検証
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?