リフレクションを利用し、private, protectedなメソッドをテストする方法について、説明します。

リフレクションとは

Wikipediaの リフレクション (情報工学) では、以下のように記されています。

情報工学においてリフレクション (reflection) とは、プログラムの実行過程でプログラム自身の構造を読み取ったり書き換えたりする技術のことを指す。

Privateメソッドを外部から呼び出す

PHPでは、リフレクションをするために、Reflectionクラスというものが用意されています。

これを利用し、テストしたいオブジェクトを読み取ります。 そして、privateメソッドを外部からアクセス可能に変更すればOKです。

UserクラスのprivateなgetNameメソッドを呼び出すには、次のようにします。

<?php
$user   = new User();
$method = new ReflectionMethod($user, 'getName');
$method->setAccessible(true);
$method->invoke($user));

汎用化

以下のようにメソッドを用意して、処理を使い回せるようにすると便利です。

<?php
abstract class TestAbstract extends TestCase
{
    /**
     * ReflectionMethodの取得
     *
     * @param mixed $testClassInstance
     * @param string $testMethodName
     * @return \ReflectionMethod
     */
    public function getReflectionMethod($testClassInstance, $testMethodName) {
        $reflectionClass = new \ReflectionClass($testClassInstance);
        $reflectionMethod = $reflectionClass->getMethod($testMethodName);
        $reflectionMethod->setAccessible(true);
        return $reflectionMethod;
    }

    /**
     * Privateなメソッドをテストする
     *
     * @param mixed $testClassInstance
     * @param string $testMethodName
     * @param array $testArgs
     * @param callable $assertAction
     * @return \ReflectionMethod
     */
    public function testPrivateMethod(
        $testClassInstance,
        $testMethodName,
        $testArgs,
        $assertAction
    ) {
        $reflectionMethod = $this->getReflectionMethod(
            $testClassInstance,
            $testMethodName
        );
        $retVal = $reflectionMethod->invokeArgs($testClassInstance, $testArgs);
        $assertAction($retVal);
    }
}

こんな感じで使います。

<?php
// Mathクラスのprivateなsumメソッドをテストします。
$math = new Math();
$this->testPrivateMethod(
    $math,
    'sum',
    [1000, 100],
    function ($retVal) {
        $this->assertEquals($retVal, 1100);
    }
);