cdruc

Testing Laravel mutators and accessors

I rarely test Laravel mutators and accessors. Mainly because usually that code is straightforward and testing it does not provide enough value to be worth the trouble.

Anyway, here's an example of a User class with a mutator and accessor for the name attribute.

class User extends Authenticable
{
    protected function name(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => ucwords($value),
            set: fn($value) => strtolower($value)
        );
    }
}

Testing accessors

An accessor is an incoming query message – you ask the object to give you something, and it so does. Test it by making assertions about what it sends back.

/** @test */
public function name_is_capitalized()
{
    $user = new User(['name' => 'constantin druc']);
    $this->assertEquals('Constantin Druc', $user->name);
}

Testing mutators

A mutator is a command message – you ask the object to change something, and so it does. Test it by making assertions about its public side effect(s). Like, did it actually change what I told it to change?

However, if your model has a mutator and an accessor for the same attribute, testing the accessor is tricky. Because if you set the name to some value and then test it by calling $user->name – the mutator will come in and alter your expected result. The only way I know how to test it is by using $user->getAttributes().

/** @test */
public function name_is_saved_in_lowercase()
{
    $user = new User();
    $user->name = 'Constantin Druc';

    $attributes = $user->getAttributes();
    $this->assertEquals('constantin druc', $attributes['name']);
}

Test query methods by making assertions on what they return, and test comand methods by making assertions on their public side effects.