Você já está se sentindo confiante com suas habilidades de teste e os seus colegas te invejam ao ouvir você falar de mocks e stubs. Mas agora, um novo desafio surge e você só pode verificar certas propriedades de um argumento, caso contrário seus testes falharão miseravelmente.
Um novo dia começa
Seu trabalho era implementar uma simples funcionalidade de cadastro de usuário. Como uma boa programadora, você planeja usar o padrão Repositório
para poder separar a camada de persistência e mocká-la em testes unitários caso necessário.
Classe usuário
Não poderia ser mais simples, certo?
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;
}
}
Repositório da entidade usuário
Não está persistindo de fato, mas vamos fingir que sim.
final class UserRepository
{
public function save(User $user): void
{
echo sprintf('Persistindo usuário com id %s e nome %s', $user->getId(), $user->getName());
}
}
Classe UserService
Agora temos uma reviravolta! Um requisito maluco diz que o campo id
deve ser randômico. Bom, temos várias maneiras de fazer isso, então vamos prosseguir:
final class UserService
{
public function __construct(private UserRepository $repository) { }
public function createNewUser(string $name): void
{
$user = new User(uniqid(), $name);
$this->repository->save($user);
}
}
Legal, tudo está funcionando.
Não vamos nos esquecer dos testes
Nós queremos verificar quando UserService
cria um User
, se o UserRepostory
está sendo chamado corretamente. Não nos importamos com a persistência agora, então podemos mockar o repositório e tudo deve funcionar.
public function testFailing(): void
{
$repository = $this->createMock(UserRepository::class);
$userService = new UserService($repository);
$repository
->expects($this->once())
->method('save')
->with(new User('id não randômico', 'user'));
$userService->createNewUser('user');
}
Infelizmente isso não funciona. O teste falha porque User
com o id id não randômico
não corresponde ao argumento passado pelo UserRepository
que tem um id diferente cada vez que um novo usuário é criado.
Captura de argumento ao resgate!
No Java, nós temos essa mesa funcionalidade provida pelo Mockito:
Captura de argumento
possibilita a verificação de apenas alguns valores do argumento ao invés de testar a equalidade do objeto inteiro.
No nosso exemplo, nós não nos precisamos testar realmente o valor do id
porque ele é gerado randomicamente pelo próprio PHP através da função uniqid
.
No final o teste usando captura de argumento
fica assim
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');
}
Obrigado por ler até aqui, espero que tenha gostado e boa sorte com seus testes!