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;
}
}
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());
}
}
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());
}
}
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());
}
}
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
Top comments (0)