4

Since Laravel 5.6, Eloquent Date Casting is available.
So I've got a model MyModel with:

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

And the factory:

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

In my unit test I'm looking for an instance of MyModel:

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

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

And that's what I get (excerpt):

Failed asserting that a row in the table [my_models] matches the attributes {
"from": "2019-01-12",
"to": "2019-02-13",
}.
Found: [{
"from": "2019-01-12 00:00:00",
"to": "2019-02-13 00:00:00",
}].

Obviously the test fails, because the time is appended at the database record's fields. They are of type date.

I could update the assertion to something like this...

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

...but that's far away from elegant.

What do I do to make this assertion succeed?

quick-brown-fox
  • 61
  • 1
  • 13

2 Answers2

2

I ended up writing a new assertion method which formats date properties of the model to Y-m-d H:i:s for a correct comparison:

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);
}
quick-brown-fox
  • 61
  • 1
  • 13
2

I also faced same problem in my case

below code change worked fine .

 $this->assertDatabaseHas('my_models', $myModel->attributesToArray());
 
 change above line to
 
 $this->assertDatabaseHas('my_models', $myModel->getAttributes());

It may work for you. instead of toArray() , attributesToArray() use getAttributes()

sradha
  • 2,216
  • 1
  • 28
  • 48