30 Days of Automated Testing:Using PHPUnit【D16】

Mocking (Part 1)

WilliamP
3 min readFeb 3, 2023

Let’s talk about “Mocking” today!

What is Mocking & Why we use mocking

The term Mocking refers to the various methods used to simulate its original behavior and function, thus isolating the object we want to test from its dependent external services. In simple terms, it is a fake of an external service. This external service can be other class functions, external APIs, file system access interfaces, and so on.

So why do we need Mocking? Here are a few scenarios to consider:

  • Let’s say we have an API that calls an external service A Service. If one day Service A goes down for maintenance, will our test code also go down or produce errors if we don’t mock Service A?
  • In the same scenario, if we want to test that our API can still work in some way even if Service A is down, how can we test this behavior if we can’t call the Service A vendor and ask them to shut down?
  • In the same scenario, if Service A hasn’t gone live yet, and we only know the expected interface and behavior, how do we test it?

In these scenarios, there’s a critical common factor that our ability to run tests depends on the external service being under our control. To break this dependency, Mocking was born!

Getting Started with Mocking

Here is an example of Mocking:

  • app/Repositories/UserRepository.php
<?php

namespace App\Repositories;

use App\Models\User;

class UserRepository
{
protected $model;

public function __construct(User $model)
{
$this->model = $model;
}

public function getUserById($userId)
{
return $this->model::find($userId);
}
}
  • app/Repositories/PostRepository.php
<?php

namespace App\Repositories;

class PostRepository
{
protected $model;
}
  • app/Services/UserService.php
<?php

namespace App\Services;

use App\Repositories\PostRepository;
use App\Repositories\UserRepository;

class UserService
{
private $userRepository;
private $postRepository;

public function __construct(
PostRepository $postRepository,
UserRepository $userRepository
) {
$this->postRepository = $postRepository;
$this->userRepository = $userRepository;
}

public function getUserData(int $userId)
{
$user = $this->userRepository->getUserById($userId);

if (empty($user)) {
return [];
}

$user->posts = $this->postRepository->getPostsByUserId($userId);

return $user;
}
}
  • tests/Feature/UserServiceTest.php
<?php

namespace Tests\Feature;

use App\Models\User;
use App\Repositories\PostRepository;
use App\Repositories\UserRepository;
use App\Services\UserService;
use Tests\TestCase;

class UserServiceTest extends TestCase
{
public function testGetUserDataWhenUserNotFound()
{
$this->mock(UserRepository::class, function ($mock) {
$mock->shouldReceive('getUserById')
->with(1)
->once()
->andReturn(null);
});

$service = app(UserService::class);

$user = $service->getUserData(1);

$this->assertEmpty($user);
}

public function testGetUserData()
{
$user = User::factory()->make();

$this->mock(UserRepository::class, function ($mock) use ($user) {
$mock->shouldReceive('getUserById')
->with(1)
->once()
->andReturn($user);
});

$this->mock(PostRepository::class, function ($mock) {
$mock->shouldReceive('getPostsByUserId')
->with(1)
->once()
->andReturn([]);
});

$service = app(UserService::class);

$user = $service->getUserData(1);

$this->assertNotEmpty($user);
$this->assertNotNull($user->posts);
}
}

In the above test code, we wrote 2 test case functions:

  • testGetUserDataWhenUserNotFound()

In this function, we mocked the behavior of the UserRepository→getUserById() function, so that even if we do not have test data prepared, we can still test whether UserService→getUserData(1) can operate normally in the scenario where UserRepository→getUserById(1) returns null.

  • testGetUserData()

In this function, we mocked the behavior of both UserRepository→getUserById() and PostRepository→getPostsByUserId(). This time, we even mocked a function PostRepository→getPostsByUserId() that has not been implemented yet!

The above is today’s first experience with Mocking, isn’t it interesting?

In the next article, let’s continue to explore more techniques about Mocking!

If you liked this article or found it helpful, feel free to give it some claps and follow the author!

Reference

Articles of This Series

--

--