Testing Laravel mutators and accessors

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. Of course, like with anything, there are cases in which it does makes sense, so do it then!

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 (mostly) a command message – you ask the object to change something, 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']);
}

I know this was a somewhat silly example, but to keep in mind, test accessors by making assertions on what they return, and test mutators by making assertions on what they’re supposed to change – the attribute value.

Leave a Reply