2018/04/16

How PHP Access Private Method And Property For Test

其實測試是不應該測 protected 以及 private method 的,但有時候為了重構,原生程式碼東西拆不夠細導致同一個 public method 執行超多的 inner method,你要在測試該 public method 中測試所有 private method 是相當痛苦的,今天來探討一下如何用 Reflection 去測試 private 的內容

<?php

class Chan
{
    private $privateName = 'A';
    private static $privateStaticName = 'B';

    private function privateFoo($name = null)
    {
        if ($name !== null) {
            return $name;
        }

        return $this->privateName;
    }

    private static function privateStaticFoo($name = null)
    {
        if ($name !== null) {
            return $name;
        }

        return self::$privateStaticName;
    }
}

這是一個叫 Chan 的 class,他包含了一般跟 static method 以及 property,現在逐步示範怎麼導出 private method 結果

使用 privateFoo
$chan = new Chan();

$reflection = new \ReflectionClass($chan);
$method = $reflection->getMethod('privateFoo');
$method->setAccessible(true);
echo $method->invoke($chan), PHP_EOL; // A
echo $method->invokeArgs($chan, array('C')), PHP_EOL; // C

這個範例中沒帶參數會返回 A,有帶參數會返回參數值

使用 privateFoo 並影響預設 property
$chan = new Chan();

$reflection = new \ReflectionClass($chan);
$method = $reflection->getMethod('privateFoo');
$method->setAccessible(true);

$property = $reflection->getProperty('privateName');
$property->setAccessible(true);
$property->setValue($chan, 'D');

echo $method->invoke($chan), PHP_EOL; // D

我們利用了 getPropery 這個方法變動了預設的 privateName 內容

使用 privateStaticFoo
$chan = new Chan();

$reflection = new \ReflectionClass($chan);

$method = $reflection->getMethod('privateStaticFoo');
$method->setAccessible(true);
echo $method->invoke($chan), PHP_EOL; // B
echo $method->invokeArgs($chan, array('E')), PHP_EOL; // E

$property = $reflection->getProperty('privateStaticName');
$property->setAccessible(true);
$property->setValue('F');
echo $method->invoke($chan), PHP_EOL; // F

基本上用法差不多,只有 invokeArgs 的时候不用傳物件進去,但測試過後其實傳也可以

沒有留言: