Create dummy objects for testing

mguinea

Marc Guinea

Posted on August 12, 2021

Create dummy objects for testing

When testing our application, we usually need to use our objects with fake data in order to cover as much as possible all combinations.

Here is where Object Mother pattern helps us.

Use case

Imagine we have the following classes that we need for any of our tests:

class UserName
{
    public function __construct(private string $value)
    {
    }

    public function value(): string
    {
        return $this->value;
    }
}

class User
{
    public function __construct(private UserName $name)
    {
    }

    public function name(): UserName
    {
        return $this->name;
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, there is an entity class called User which contains a value object called UserName corresponding to the name attribute.

Instead of forcing its values in a test (which will make it weak, because it tests the same data each time) we can use the pattern Object Mother.

Object Mother pattern gives us the benefits of auto generating dummy data plus force it to fixed value if required.

Implementation

In our example case we need a UserNameMother and UserMother classes. Let's see how to implement them:

class UserNameMother
{
    public static function create(?string $value = null): UserName
    {
        $random = ['Marc', 'Anna', 'Júlia', 'Ivet'];

        return new UserName($value?->value() ?? $random[rand(0, count($random) - 1)]);
    }
}

class UserMother
{
    public static function create(?UserName $name = null): User
    {
        return new User($name?->value() ?? UserNameMother::create()->value());
    }
}
Enter fullscreen mode Exit fullscreen mode

We have set 4 different names that will be set randomly, but using a fake data provider like FakerPHP we can achieve a bigger set of data.

Usage

Let's see how to use it in our test.

class SomeTest extends TestCase
{
    /** @test */
    public function itShouldAssertSomething(): void
    {
        $user = UserMother::create();

        $this->assertNotNull($user->name());
    }
}
Enter fullscreen mode Exit fullscreen mode

Sometimes we need to have a no random attribute, so we can force it. In the next example, we force the name to 'John' value:

class SomeTest extends TestCase
{
    /** @test */
    public function itShouldAssertSomething(): void
    {
        $user = UserMother::create(
            UserNameMother::create('John')
        );

        $this->assertEquals('John', $user->name()->value());
    }
}
Enter fullscreen mode Exit fullscreen mode

If we had more attributes, depending on the test, we can combine random and fixed values.

Conclusion

Our example is really simple and silly, but imagine the flexibility of that approach; your tests can use a huge amount of combinations when required giving them more strength and coverage.

Special thanks to Christian Puga

💖 💪 🙅 🚩
mguinea
Marc Guinea

Posted on August 12, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related