phpUnit – 如何測試類別中的保護或私有方法

通常在 phpUnit 中, 為了避免過度設計,要測試的方法都是 Class 的公開方法。但有時候我們要對受保護的方法或私有方法、甚至是屬性作測試,那該如何測試寫?

我們可以藉由 「ReflectionClass 反射類別 / ReflectionMethod 反射方法」 來達到,以下是 phpUnit 運行在路徑 tests/ 底下的範例

<?php

namespace Tests;

use PHPUnit\Framework\TestCase;

// 受測範例
class User
{
    protected static function getPhone($name)
    {
        return "{$name}: 09123456789";
    }

    private function search($id, $name)
    {
        return "{$id} - {$name}";
    }
}

// 測試 User 類別
class MyTest extends TestCase
{
    // 測試靜態保護的方法
    public function testProtectedStaticMethod()
    {
        // 直接反射方法
        $reflectionMethod = new \ReflectionMethod(User::class, 'getPhone');
        $reflectionMethod->setAccessible(true);

        // 代入該方法的參數
        $result = $reflectionMethod->invoke(new User(), "Cary");
        $this->assertEquals("Cary: 09123456789", $result);
    }

    // 測試私有方法
    public function testPrivateMethod()
    {
        // 直接反射方法
        $reflectionMethod = new \ReflectionMethod(User::class, 'search');
        $reflectionMethod->setAccessible(true);

        // 代入該方法的參數
        $result = $reflectionMethod->invoke(new User(), "500800", "Cary");
        $this->assertEquals("500800 - Cary", $result);
    }

    // 混和測試
    public function testMix()
    {
        // 只反射類別
        $reflectionClass = new \ReflectionClass(User::class);

        // 從反射的類別下去取得靜態方法
        $method = $reflectionClass->getMethod('getPhone');
        $method->setAccessible(true);

        // 為該方法帶入參數
        $invoke = $method->invoke(new User(), 'Cary');

        // 從反射的類別下去取得方法
        $method = $reflectionClass->getMethod('search');
        $method->setAccessible(true);

        // 為該方法帶入參數
        $invoke = $method->invoke(new User(), '500800', 'Cary');
    }

}

至於何時用 ReflectionClass 或 ReflectionMethod,如果要同時測試 Class 底下多個 Methods,那麼使用 ReflectionClass 會方便一點;如果只是單純測試某個 Methods 那麼就使用 ReflectionMethod 。

參考來源

發表迴響