In previous articles, we've seen how it's possible to write your own mocks, and also how easier it is to use PHPUnit built-in mocking mechanism. We've then finally looked at one of the most popular PHP mocking library: Mockery.

We'll now look at an alternative one called Phake. We will compare the two and what their pros and cons are.

Phake is certainly less famous than Mockery, however it has a slightly different approach to mocking in some cases. It's worth noting that it's heavily inspired by Mockito, a Java mocking library.

Case study

In order to compare these libraries appropriately, let's reuse our example from the previous articles.

The following PostService class takes as dependencies a doctrine entity manager and a repository.

It also has two public methods that we will want to test :

- one to create a post

- one to retrieve a post from the DB

<?php

namespace App;

use Doctrine\ORM\EntityManagerInterface;

class PostService
{
    /** @var EntityManagerInterface */
    private $entityManager;

    /** @var PostRepository  */
    private $postRepository;

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

    public function createPost(Post $post): void
    {
        $this->entityManager->persist($post);
        $this->entityManager->flush();
    }

    public function getPost(int $id): Post
    {
        /** @var Post|null $post */
        $post = $this->postRepository->find($id);
        if (is_null($post)) {
            throw new \RuntimeException('Post not found');
        }

        return $post;
    }
}

 

Installation

Just like with Mockery, Phake can be installed with composer:

composer require --dev phake/phake

 

Now that it's installed, let's have a look at unit testing this service class.

Unit tests

<?php

namespace App\Tests\Phake;

use App\Post;
use App\PostRepository;
use App\PostService;
use Doctrine\ORM\EntityManagerInterface;
use Phake;
use Phake_IMock;
use PHPUnit\Framework\TestCase;

class PostServiceTest extends TestCase
{
    private const POST_ID = 1;

    /** @var PostRepository|Phake_IMock */
    private $postRepository;

    /** @var EntityManagerInterface|Phake_IMock */
    private $entityManager;

    /** @var PostService */
    private $service;

    protected function setUp(): void
    {
        $this->postRepository = Phake::mock(PostRepository::class);
        $this->entityManager = Phake::mock(EntityManagerInterface::class);
        $this->service = new PostService($this->entityManager, $this->postRepository);
    }

    public function testGetPost(): void
    {
        $expected = new Post();
        Phake::when($this->postRepository)->find(self::POST_ID)->thenReturn($expected);

        $actual = $this->service->getPost(self::POST_ID);

        $this->assertSame($expected, $actual);
    }

    public function testGetPost_PostNotFound(): void
    {
        $this->expectException(\RuntimeException::class);

        $this->service->getPost(self::POST_ID);
    }

    public function testCreatePost(): void
    {
        $post = new Post();

        $this->service->createPost($post);

        Phake::verify($this->entityManager)->persist($post);
        Phake::verify($this->entityManager)->flush();
    }
}

 

We can notice a few similarities with Mockery:

- we use a static call to Phake::mock to instantiate our mocks.

- we can define behaviours fairly easily for each mock's methods.

 

However, there are some differences in the approach and syntax:

- Phake doesn't need to include any PHP trait to be able to make assertions in PHPUnit (compared to Mockery's MockeryPHPUnitIntegration trait)

- We use Phake::when to define an expected outcome of a method (return statement, throwing an exception...)

- In testGetPost_PostNotFound, we didn't define any expected outcome. That's because by default Phake methods will return null, which is what we wanted here.

- Phake::verify is used to assert an excepted call has been made to the mock. This is a fairly big difference compared to Mockery for two reasons:

   1. Mockery uses the same call to the expects method to both define an expected outcome and verify that a call was made.

   2. Phake::verify is called after the method call takes place, just like a regular PHPUnit assertion. This is in my opinion way more logical.

 

I personally prefer Phake's syntax than Mockery's. It's more straightforward, the distinction between Phake::when and Phake::verify gives a clearer intent, and verifying calls at the end of the test is more instinctive.

 

This is however a matter of personal preferences, as both Mockery and Phake present similar functionalities. 

Here is a link to Phake's documentation if you are interested.