👨‍🔧

PHPUnitでprivateのメソッド、プロパティのテストを書く

2022/09/14に公開

はじめに

privateメソッドのテストを書く必要があったときにやったことをメモしておきます。

環境

  • PHP 8.1.9
  • PHPUnit 9.5.24

サンプルコード

適当にprivateのプロパティとメソッドがあるクラスを作成しています。

<?php

declare(strict_types=1);

namespace App;

class Sample
{
    private int $privateProperty = 1;

    private function privateMethod(int $a): bool
    {
        return $a > 5;
    }
}

上記クラスのテストクラスはこちらです。

<?php

declare(strict_types=1);

namespace Tests;

use App\Sample;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

class SampleTest extends TestCase
{
    /**
     * privateメソッドのテスト
     */
    public function testPrivateMethod(): void
    {
        $sample = new Sample();

        $reflection = new ReflectionClass($sample);

        // 引数にはprivateメソッド名を指定する
        $method = $reflection->getMethod('privateMethod');

        // アクセス許可
	// PHP 8.1以降では呼び出しが不要になりました
	// https://www.php.net/manual/ja/reflectionmethod.setaccessible.php
        // $method->setAccessible(true);

        // メソッド実行
        // 第二引数以降にはprivateメソッドの引数を指定する
        $result = $method->invoke($sample, 6);

        // 検証
        $this->assertTrue($result);
    }

    /**
     * privateプロパティのテスト
     */
    public function testPrivateProperty(): void
    {
        $sample = new Sample();

        $reflection = new ReflectionClass($sample);

        // 引数にはprivateプロパティ名を指定する
        $property = $reflection->getProperty('privateProperty');

        // アクセス許可
	// PHP 8.1以降では呼び出しが不要になりました
	// https://www.php.net/manual/ja/reflectionproperty.setaccessible.php
        // $property->setAccessible(true);

        // 値の取得
        $value = $property->getValue($sample);

        // 検証
        $this->assertSame(1, $value);

        // 値の上書き
        $property->setValue($sample, 2);

        // 値の取得
        $value = $property->getValue($sample);

        // 検証
        $this->assertSame(2, $value);
    }
}

実行結果

$ vendor/bin/phpunit tests/SampleTest.php 
PHPUnit 9.5.24 #StandWithUkraine

..                                                                  2 / 2 (100%)

Time: 00:00.114, Memory: 8.00 MB

OK (2 tests, 3 assertions)

まとめ

今回privateメソッドを直接実行するためのテストを書いてみました。
ReflectionClassクラスを使うと簡単に実行することができることがわかりました。

ただし、privateメソッドを直接テストを書くよりは、publicメソッドを経由してテストを書く方が個人的には良い気もします。

Discussion