Laravel 8 - PHPUnit Test problem using "Date Mutators" and Faker

847 views Asked by At

I noticed that setting a Date Mutator field in protected dates array into the Model, the date format used in the Faker are modified as Carbon object and do not return the format set in the Faker; is this normal?

To explain the problem, the Model is something like:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Post extends Model
{
    use HasFactory;

    protected $dates = [
        'seen_at'
    ];

    // other code here...
}

the Factory class contains:

<?php
namespace App\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use App\Models\Post;

class PostFactory extends Factory
{
    protected $model = Post::class;
    public function definition()
    {
        return [
            'number'         => $this->faker->randomDigit,
            'seen_at'        => $this->faker->date($format = 'Y-m-d\TH:i:s.vP', $max = 'now'),
            'quality'        => $this->faker->unique()->regexify('[A-D][A-D]'),
        ];
    }
}

and the Test class is:

<?php
namespace App\Tests\Feature;

use Tests\TestCase;
use App\Factories\PostFactory;

class PostControllerTest extends TestCase
{
    public function setUp(): void
    {
        parent::setUp();

        $post = PostFactory::new()->make();
        dd($post->seen_at);

        // other code here....
    }
}

Runnig the Test, the dd() returns:

Illuminate\Support\Carbon @228109214 {#2283
  #constructedObjectId: "00000000486a8e5f00000000514b58c9"
  #localMonthsOverflow: null
  #localYearsOverflow: null
  #localStrictModeEnabled: null
  #localHumanDiffOptions: null
  #localToStringFormat: null
  #localSerializer: null
  #localMacros: null
  #localGenericMacros: null
  #localFormatFunction: null
  #localTranslator: null
  #dumpProperties: array:3 [
    0 => "date"
    1 => "timezone_type"
    2 => "timezone"
  ]
  #dumpLocale: null
  date: 1977-03-25 03:40:14.0 +00:00
}

the date do not match the format specified into the Faker, that should be 'Y-m-d\TH:i:s.vP'; but is 1977-03-25 03:40:14.0 +00:00.

If I remove the seen_at from protected $dates array, running the test again the output is correctly:

"1970-02-10T03:13:34.000+00:00"

Another think is that if I dd() the entire Model generate from Faker with protected $dates that contains seen_at:

class PostControllerTest extends TestCase
{
    public function setUp(): void
    {
        parent::setUp();

        $post = PostFactory::new()->make();
        dd($post);

        // other code here....
    }
}

the output it contains correct date:

App\Models\Post {#2399
  #table: "post"
  . . .
  #attributes: array:39 [
    "number" => 8
    "seen_at" => "1970-02-10T03:13:34.000+00:00"
    "quality" => "AB"
  ]
  . . .
  #guarded: array:1 [
    0 => "*"
  ]
}

Is this behaviour normal? If "yes", how I can return the correct date format?

Thank you.

1

There are 1 answers

0
Preda Alexandru On

Me and my colleague had the same issue. We worked around it like this:

   class PostTest extends TestCase
   {
    public function test_can_create_post() {
        $data = [
            ...//data
            'seen_at' => $this->faker->date(),
        ];

        $post = null;

        try {
            $post = Post::create($data);
        } catch (QueryException $e) {
            throw $e;
        }
        
        $this->assertInstanceOf(Post::class, $post);
        ...
        $this->assertEquals($data['seen_at'].' 00:00:00', $post->seen_at);
    }
}

And my TestCase class looks like this:

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Foundation\Testing\WithFaker;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, WithFaker;
}

With this configuration, the test passes successfully!!