🦍

[Laravel]assertDatabaseHasの第一引数にはテーブル名ではなく、Modelを渡そう!

2023/08/30に公開

結論

  • Before
$this->assertDatabaseHas('users', ['id' => 1]);
  • After
$this->assertDatabaseHas(User::class, ['id' => 1]);

他にも、様々な形でテーブルを指定することが可能です。下記の書き方は全て同じ挙動をします。

$this->assertDatabaseHas('users',*);
$this->assertDatabaseHas(new User(),*)
$this->assertDatabaseHas((new User())->getTable(),*)
$this->assertDatabaseHas(User::getModel()->getTable(),*)

内部実装の解説

assertDatabaseHasの第一引数の$tableは、EloquentModelもしくはstringを受け取ります。

    /**
     * Assert that a given where condition exists in the database.
     *
     * @param  \Illuminate\Database\Eloquent\Model|string  $table
     * @param  array  $data
     * @param  string|null  $connection
     * @return $this
     */
    protected function assertDatabaseHas($table, array $data, $connection = null)
    {
        $this->assertThat(
            $this->getTable($table), new HasInDatabase($this->getConnection($connection), $data)
        );

        return $this;
    }

getTableメソッドでは、EloquentModelクラスならインスタンスを作成し、getTable()でテーブル名を取得しています。

/**
     * Get the table name from the given model or string.
     *
     * @param  \Illuminate\Database\Eloquent\Model|string  $table
     * @return string
     */
    protected function getTable($table)
    {
        return is_subclass_of($table, Model::class) ? (new $table)->getTable() : $table;
    }

https://www.php.net/manual/ja/function.is-subclass-of.php

まとめ

テーブル名を直接指定するのではなく、モデル経由で指定することでIDEの補完を受けやすくなります。加えて、テーブル名を変更した際に、テストコードへ影響しなくなるのもメリットだと思いました。
assertDatabase*系のメソッドにおいて、テーブル名は全て上記の方法で指定可能です。
公式には書かれていないが、便利なメソッドや引数の渡し方が存在する場合が多いので、定期的に書こうと思います。

マナリンク Tech Blog

Discussion