Fakerの日時データ表示形式が合わないので、PHPUnitテストに失敗する - d-sazanami/laravel-jissenkaihatsu-v1 GitHub Wiki

現象

ファクトリを使ってテストデータを生成したところ、日付カラムのデータがファクトリで生成された日付とデータベース上のデータと形式が異なってしまっているため、テストが失敗した

1) Tests\Feature\ExampleTest::testBasicTest
Failed asserting that a row in the table [people] matches the attributes {
    "id": 67,
    "name": "Dolly Schiller",
    "mail": "[email protected]",
    "created_at": "2022-03-12T06:45:23.000000Z",
    "updated_at": "2022-03-12T06:45:23.000000Z",
    "age": 38
}.

Found similar results: [
    {
        "id": 67,
        "name": "Dolly Schiller",
        "mail": "[email protected]",
        "created_at": "2022-03-12 15:45:23",
        "updated_at": "2022-03-12 15:45:23",
        "age": 38
    }
].

前提

config/app.php

return [
    'timezone' => 'Asia/Tokyo',
    'locale' => 'ja',
    'faker_locale' => 'en_US',

調査

$person = Person::find(rand(1, $count)); の変数を var_dump してみる。

# vendor/bin/phpunit
PHPUnit 9.5.16 by Sebastian Bergmann and contributors.

..F                                                                 3 / 3 (100%)/var/www/html/tests/Feature/ExampleTest.php:33:
class App\Models\Person#1601 (30) {
  protected $connection =>
  string(7) "testing"
  protected $table =>
  string(6) "people"
  protected $primaryKey =>
  string(2) "id"
  protected $keyType =>
  string(3) "int"
  public $incrementing =>
  bool(true)
  protected $with =>
  array(0) {
  }
  protected $withCount =>
  array(0) {
  }
  public $preventsLazyLoading =>
  bool(false)
  protected $perPage =>
  int(15)
  public $exists =>
  bool(true)
  public $wasRecentlyCreated =>
  bool(false)
  protected $escapeWhenCastingToString =>
  bool(false)
  protected $attributes =>
  array(6) {
    'id' =>
    int(70)
    'name' =>
    string(18) "Emilio Schiller II"
    'mail' =>
    string(24) "[email protected]"
    'created_at' =>
    string(19) "2022-03-13 08:19:26"
    'updated_at' =>
    string(19) "2022-03-13 08:19:26"
    'age' =>
    int(99)
  }
  protected $original =>
  array(6) {
    'id' =>
    int(70)
    'name' =>
    string(18) "Emilio Schiller II"
    'mail' =>
    string(24) "[email protected]"
    'created_at' =>
    string(19) "2022-03-13 08:19:26"
    'updated_at' =>
    string(19) "2022-03-13 08:19:26"
    'age' =>
    int(99)
  }
  protected $changes =>
  array(0) {
  }
  protected $casts =>
  array(0) {
  }
  protected $classCastCache =>
  array(0) {
  }
  protected $attributeCastCache =>
  array(0) {
  }
  protected $dates =>
  array(0) {
  }
  protected $dateFormat =>
  NULL
  protected $appends =>
  array(0) {
  }
  protected $dispatchesEvents =>
  array(0) {
  }
  protected $observables =>
  array(0) {
  }
  protected $relations =>
  array(0) {
  }
  protected $touches =>
  array(0) {
  }
  public $timestamps =>
  bool(true)
  protected $hidden =>
  array(0) {
  }
  protected $visible =>
  array(0) {
  }
  protected $fillable =>
  array(0) {
  }
  protected $guarded =>
  array(1) {
    [0] =>
    string(2) "id"
  }
}
Array
(
    [id] => 70
    [name] => Emilio Schiller II
    [mail] => [email protected]
    [created_at] => 2022-03-12T23:19:26.000000Z
    [updated_at] => 2022-03-12T23:19:26.000000Z
    [age] => 99
)


Time: 00:09.594, Memory: 32.00 MB

There was 1 failure:

1) Tests\Feature\ExampleTest::testBasicTest
Failed asserting that a row in the table [people] matches the attributes {
    "id": 70,
    "name": "Emilio Schiller II",
    "mail": "[email protected]",
    "created_at": "2022-03-12T23:19:26.000000Z",
    "updated_at": "2022-03-12T23:19:26.000000Z",
    "age": 99
}.

Found similar results: [
    {
        "id": 70,
        "name": "Emilio Schiller II",
        "mail": "[email protected]",
        "created_at": "2022-03-13 08:19:26",
        "updated_at": "2022-03-13 08:19:26",
        "age": 99
    }
].

/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php:29
/var/www/html/tests/Feature/ExampleTest.php:36

FAILURES!
Tests: 3, Assertions: 3, Failures: 1.

日付カラムのデータが、オブジェクトの $attributes$original では、 Y-m-d H:i:s 形式だが、 ArraytoArray 後のオブジェウトを見ると、ISO-8601形式になっている。 attributesToArray でも見てみたが、ISO-8601形式で日付が保持される。

デフォルトの日付形式のカスタマイズはできる

https://readouble.com/laravel/8.x/ja/eloquent-serialization.html にある通り、 serializeDate メソッドを実装できれば良い。 そのまま Person モデル・クラスにこのメソッドを書いてみたが、

serializeDate-not-compatible

になる。 Illuminate\Database\Eloquent\Model にはじかに、serializeDate メソッドが定義されていなかった。 vendor ディレクトリ以下をメソッド名で検索しても、該当ファイルは見つからなかったので、よくわからなかった。

対応

日付の表示形式は、全体的に変えたいことが多いので、 https://qiita.com/kenkubomi/items/58d026733266a30e801a に習って、トレイトで実装することで、解決した。