首页 > 解决方案 > 在数据库中搜索模型时,由于日期时间格式测试失败

问题描述

从 Laravel 5.6 开始,Eloquent Date Casting可用。
所以我有一个模型MyModel

class MyModel extends Model {
    protected $casts = ['from' => 'date:Y-m-d', 'to' => 'date:Y-m-d'];
    protected $dates = ['from', 'to'];
}

和工厂:

$factory->define(MyModel::class, function(Faker $faker) {
    return [
        'from' => Carbon::instance($faker->dateTime),
        'to' => Carbon::instance($faker->dateTime),
        // some more attributes
    ];
}

在我的单元测试中,我正在寻找MyModel的一个实例:

/** @test */
public function example() {
    $myModel = factory(MyModel::class)->create();

    $this->assertDatabaseHas('my_models', $myModel->attributesToArray());
}

这就是我得到的(摘录):

无法断言表 [my_models] 中的行与属性 {
“from”:“2019-01-12”、
“to”:“2019-02-13”、
} 匹配。
找到:[{
“from”:“2019-01-12 00:00:00”,
“to”:“2019-02-13 00:00:00”,
}]。

显然测试失败了,因为时间附加在数据库记录的字段中。它们是类型date

我可以将断言更新为这样的东西......

$this->assertDatabaseHas('my_models', [
    'from' => $myModel->from->toDateTimeString(),
    'to' => $myModel->to->toDateTimeString(),
] + $myModel->attributesToArray());

...但这远非优雅。

我该怎么做才能使这个断言成功?

标签: phplaravelphpunit

解决方案


我最终编写了一个新的断言方法,该方法将模型的日期属性格式化Y-m-d H:i:s为正确比较:

protected function assertDatabaseHasModel(string $table, Model $model, ?string $connection = null): void
{
    $attributes = $model->attributesToArray();
    $reflection = new ReflectionClass($model);
    $property = $reflection->getProperty('casts');
    $property->setAccessible(true);

    collect($property->getValue($model))->each(function (string $cast, string $field) use ($model, &$attributes) {
        if (Str::startsWith($cast, 'date:')) {
            $attributes[$field] = $model->$field->toDateTimeString();
        } elseif (in_array($cast, ['array', 'object'], true) && $model->$field !== null) {
            $attributes[$field] = $this->castAsJson($model->$field);
        }
    });

    $this->assertDatabaseHas($table, $attributes, $connection);
}

推荐阅读