Laravel内で共通のことですがクラス中で用いる初期化関数__construct()が上手く働かないことがあります。これに陥る原因としてLaravel内でクラスを呼び出した時、まだインスタンス化されていないクラスに関わる関数を呼び出すというものがあります。Laravelの組み込み関数や定義したEloquentによる関数、プロパティは便利ですが__construct()内では使えません。duskも同様です。
Laravel内で用いられているクラスはこれを解決するために、前処理が終わった後、本処理が始まる前に呼び出される関数をboot,setupなどといった名前で定義しています。__construct()の次にboot()が走り、boot()の次にコントローラなどの本処理が走るといった具合です。duskではsetUp()という名前で定義されています。このsetUp()関数内でテストに使うデータを定義すると幾分かすんなりとテストを記述できます。例えば次です。
/**
* @inheritDoc
*/
protected function setUp()
{
parent::setUp();
// テストに用いる編集対象の管理者を指定、インスタンス化
$admin_key = static::$admin_key ?? Admins::inRandomOrder()->first()->getKey();
$this->admin = Admins::findOrFail($admin_key);
}
あらかじめ特定の管理者を対象にするならばその管理者を、そうでないならばランダムに選んだ管理者を対象にして様々なテストに用います。
開始に対応するように終了時にフックされる関数もあります。dusk内ではtearDownとされています。あるテストが終わるたびにtearDown関数が呼ばれているため、ブラウザテストの完全終了を待たずともあるテストケースの失敗とそれを解決するための情報を得る記述をすることが出来ます。tests/DuskTestCase.phpを継承することで各テストケースがブラウザ上で走るため、tests/DuskTestCase内に次の様に記述するのが良いでしょう。DuskTestCaseより深く潜るとvendorの領域に入ってしまいます。
/**
* @inheritDoc
*/
protected function tearDown()
{
parent::tearDown();
if ($this->hasFailed()) {
dump('failed in ' . static::class . '::' . $this->getName() . '. test case instance is');
$test_class_data = (new \Illuminate\Support\Collection($this))->filter(function ($value, $key) {
return !strpos($key, 'PHPUnit');// 2、3000行程になるPHPUnit自体の情報を削除
});
dump($test_class_data);
}
}