なおのつぼやき

Webエンジニアです。PHP/Laravel、あとRustを少々

Mockeryを使った時にprotectedメソッドのモックを作る

こんなクラスがありました

<?php

class TestClass
{
    public function aaaa(): string
    {
        return $this->bbbb();
    }

    protected function bbbb(): string
    {
        return 'bbbb';
    }
}

これをMockeryを使ってbbbbメソッドの返す値を変えようと思います

<?php

use PHPUnit\Framework\TestCase;
use Mockery as m;

class TestClassTest extends TestCase
{
    public function test1(): void
    {
        $mock = m::mock(TestClass::class)
            ->makePartial();
        $mock->shouldReceive('bbbb')-> andReturn('cccc');

        $this->assertSame('cccc', $mock->aaaa());
    }
}

このテストを実行すると次のようなエラーが出てきます

$ vendor/bin/phpunit tests/TestClassTest.php 
PHPUnit 9.2.6 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 00:00.043, Memory: 4.00 MB

There was 1 error:

1) Tests\TestClassTest::test1
InvalidArgumentException: bbbb() cannot be mocked as it is a protected method and mocking protected methods is not enabled for the currently used mock object. Use shouldAllowMockingProtectedMethods() to enable mocking of protected methods.

protectedメソッドは普通にやるとモックにはできないようです
エラーメッセージに書いてある通りshouldAllowMockingProtectedMethods()を使って書き直してみます

<?php

use PHPUnit\Framework\TestCase;
use Mockery as m;

class TestClassTest extends TestCase
{
    public function test1(): void
    {
        $mock = m::mock(TestClass::class)
            ->shouldAllowMockingProtectedMethods() // この1行を追加
            ->makePartial();
        $mock->shouldReceive('bbbb')-> andReturn('cccc');

        $this->assertSame('cccc', $mock->aaaa());
    }
}

あたらめて実行

$ vendor/bin/phpunit tests/TestClassTest.php 
PHPUnit 9.2.6 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:00.057, Memory: 4.00 MB

OK (1 test, 1 assertion)

成功です

一応、マニュアルに書いてありましたね readouble.com