Argument capture in PHP tests

Photo by Ben Griffiths on Unsplash

You’re already feeling confident with your test skills and all your teammates envy you talking about mocks and stubs. But now you’re faced with a new challenge, you only need to verify some properties of an argument, otherwise your tests will fail miserably.

Oh no, tests are failing!

Sunny day starts

Your job was to implement a simple user registration feature. As a good programmer you planned this to use the Repository pattern so you could separate the persistence layer and mock it in unit tests if necessary.

Wait, this is too easy to be true

User class

Couldn’t be simpler, right?

final class User
{
public function __construct(
private string $id,
private string $name)
{
}
public function getId(): string
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
}

UserRepository

Not doing any persistence, but let’s pretend it is.

final class UserRepository
{
public function save(User $user): void
{
echo sprintf('Persisted user with id %s and name %s', $user->getId(), $user->getName());
}
}

UserService

Now we have some plot twist! Some crazy requirements arrived from above and it says the id field should be randomic. Well, there's a lot of ways to achieve this so you just go on:

final class UserService
{
public function __construct(private UserRepository $repository) { }
public function createNewUser(string $name): void
{
$user = new User(uniqid(), $name);
$this->repository->save($user);
}
}

Cool, everything is working.

Wait, let’s not forget the tests

We should, definitely

We want to verify when the UserService creates an User, if the UserRepository is being called with correctly. We don't care now about the persistence, so we can just mock the repository and everything should work fine.

public function testFailing(): void
{
$repository = $this->createMock(UserRepository::class);
$userService = new UserService($repository); $repository
->expects($this->once())
->method('save')
->with(new User('not so random id', 'user'));
$userService->createNewUser('user');
}

Until it doesn’t. That test fails because User with not so random id doesn't match the argument called by UserRepository which has a different id each time a new user is created.

Argument capture to the rescue!

In Java we have this same feature enabled by Mockito:

Argument Capture allows us to create assertions on certain values of the arguments, instead of testing the equality for the whole object.

In our example we don’t need to test the id value, since it's randomic and it's being generated by PHP itself using the uniqidfunction.

In the end this is how the test using argument capture looks like:

public function testRepositoryShouldCreateUserWithCorrectName(): void
{
$repository = $this->createMock(UserRepository::class);

$userService = new UserService($repository);

$repository
->expects($this->once())
->method('save')
->will($this->returnCallback(function($user) {
self::assertEquals('user', $user->getName());
}));

$userService->createNewUser('user');
}

Thanks for reading this far, hope you enjoyed and good luck with your tests!

--

--

--

fabiothiroki.github.io

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

DevOps using Legacy Systems and Applications? Here’s How!

DevOps using Legacy Systems and Applications? Here’s How!

Getting Started With CSS: What is CSS in Web Development, and how to use it?

1000 Followers on Mobile App Development Publication

The Ultimate Setup Guide for Google Tag Manager

Control the Flow of Your Program In Python

Audio And Video Player Application Using Flutter

Lodestar Medalla Update

Difference Between Edge and Cloud Computing Technologies

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Fabio Hiroki

Fabio Hiroki

fabiothiroki.github.io

More from Medium

PHP fundamentals — part 1

Singleton Pattern — PHP Implementation

pre_fetch_count in common cases in PHP

Calculate PHP cache time with ease