Urbycoz
Urbycoz

Reputation: 7421

How should I correctly construct my unit test in Laravel

I am quite new to unit testing and could do with a bit of guidance. I am trying to write a simple unit test using the Factory pattern in Laravel and phpunit for an application that allows you to add Companies to a database.

I have a Company Model Company.php, a Factory class which uses it CompanyFactory.php, and finally the unit test itself CompaniesTest.php.

Models/Company.php

namespace App\Models;

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

class Company extends Model
{
    use HasFactory;
    protected $table = 'companies';
    protected $fillable = [
        'name',
        'email'
    ];
}

Database/Factories/CompanyFactory.php

namespace Database\Factories;

use App\Models\Company;
use Illuminate\Database\Eloquent\Factories\Factory;

class CompanyFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Company::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => $this->faker->name,
            'email' => $this->faker->email,
            'created_at' => now(),
            'updated_at' => now(),
        ];
    }
}

Tests/Feature/CompaniesTest.php

namespace Tests\Unit;
        
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Models\Company;
use Tests\TestCase;
use Illuminate\Support\Str;
use Illuminate\Foundation\Testing\WithFaker;

class CompanyTest extends TestCase
{
    use WithFaker, DatabaseTransactions;

    public function createCompany($name = NULL)
    {
        if ($name == NULL) $name = Str::random(6);

        $company = Company::factory()->create([
            'name' => 'TestName_'.$name
        ]);

        return $company->id;
    }


    /** @test */
    public function company_can_be_created()
    {
        $name = Str::random(6);

        //Create a company
        $company_id = $this->createCompany($name);

        //Check whether the company name exists in the database
        $this->assertDatabaseHas('companies', [
            'name' => 'TestName_'.$name
        ]);
    }
}

The test seems to work, but it feels like I might have over-complicated it and probably not followed the correct conventions.

What would be a better way to structure it?

Upvotes: 2

Views: 2630

Answers (1)

Ilia Yatsenko
Ilia Yatsenko

Reputation: 832

The test looks ok, but what are you actually testing? It seems to me that this test is testing the framework's code, which is actually not what you should do.

Don't test a factory, use it to prepare the data needed before each test. And then run your actual code which you want to test, and assert results.


Update: Continue with CompanyVerifier (see comments). Suppose company can be valid and non-valid. Valid companies can be verified. Then a test may look like:

/** @test */
public function test_valid_company_can_be_verified()
{
    // here use a CompanyFactory with some pre-defined data to create "valid" company
    $validCompany = $this->createValidCompany();

    // here goes the actual code of SUT (system under test)
    $verifier = new CompanyVerifier();
    $result = $verifier->verify($validCompany);

    // here check results
    $this->assertTrue($result);
}

The good practice for testing is named AAA (arrange-act-assert). Here the creation of a company with some state is an "arrange" stage. Running tested code is "act". And assert is "assert".

Factories are just a helper for "arrange" stage.

Upvotes: 4

Related Questions