CakePHP 3 のコントローラにある private や protected な関数をテストする方法

はじめに

CakePHP 3 には PHPUnit でテストするための機能が整っています。
bake コマンドを使ってコントローラなどを生成すれば、自動的にテスト用のファイルも生成されます。

CakePHP 3 の公式ドキュメントの下記ページでは、コントローラのテスト方法について説明されています。
しかし、アクション以外の private、protected メソッドのテスト方法については書かれていません。

今日は CakePHP 3 のコントローラ内にある private や protected な関数のテストを行う方法をご紹介します。

CakePHP
3.8.5
PHPUnit
6.5.14

テスト実装方法

例として、下記コントローラの checkAnswer 関数のテストを行う場合を想定します。

この関数は引数の $answer が 試験 だったら true、異なれば false を返します。

/src/Controller/SampleController.php
<?php
namespace App\Controller;

use App\Controller\AppController;

class SampleController extends AppController
{
    private function checkAnswer($answer)
    {
        return ($answer === '試験');
    }
}

この checkAnswer() をテストするには下記のように実装します。

/tests/TestCase/Controller/SampleControllerTest.php
<?php
namespace App\Test\TestCase\Controller;

use App\Controller\SampleController;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
use ReflectionClass; // ←これが必要

class SampleControllerTest extends TestCase
{
    use IntegrationTestTrait;

    public function testCheckAnswer()
    {
        $sampleCtrl = new SampleController();
        $ref = new ReflectionClass($sampleCtrl);

        $checkAns = $ref->getMethod('checkAnswer');
        $checkAns->setAccessible(true);

        $result = $checkAns->invoke($sampleCtrl, '試験');
        $this->assertTrue($result);
    }
}

private や protected なメソッドを呼び出すためには、ReflectionClassを利用することができます。

下から4行目にある invoke() の第二引数が、checkAnswer()への引数になります。テストしたい関数の引数が2個以上ある場合は、下記のように続けて書けばOKです。

// checkAnswer($ans1, $ans2, $ans3) のような場合
$result = $checkAns->invoke($sampleCtrl, '試験', 'しけん', 'シケン');