Рецепты для тестирования

Замена защищенных и приватных свойств

Если вам понадобился данный трюк то скорее всего вы имеете проблему в архитектуре вашего класса/приложения. Его использование это крайняя мера. Лучше всего тестировать приватные свойства и методы через публичные методы. Использование данного трюка оправдано в случае экономии времени и только, как временное решение.

Пример тестируемого класса:

class Suit {

	private $private_property = 'private property value';

	public function get_private_property(): string {
		return $this->private_property;
	}

}

Для замены защищенного/приватного свойства нам понадобится все тот же ReflectionProperty. Создадим метод update_inaccessible_property:

private function update_inaccessible_property( $object, string $property_name, $value ) {
	$property = new ReflectionProperty( $object, $property_name );
	$property->setAccessible( true );
	$property->setValue( $object, $value );
	$property->setAccessible( false );
}

Разберем построчно:

  • С помощью ReflectionProperty получаем в виде объекта свойство private_property объекта класса Suit;
  • Делаем свойство доступным для редактирования;
  • Устанавливаем для свойства private_property объекта класса Suit новое значение;
  • Делаем свойство недоступным для редактирования;

Пример теста полностью:

use PHPUnit\Framework\TestCase;
use ReflectionProperty;

class Test_Suit extends \PHPUnit\Framework\TestCase {

	private function read_inaccessible_property( $object, string $property_name ) {
		$property = new ReflectionProperty( $object, $property_name );
		$property->setAccessible( true );
		$value = $property->getValue( $object );
		$property->setAccessible( false );

		return $value;
	}

	private function update_inaccessible_property( $object, string $property_name, $value ) {
		$property = new ReflectionProperty( $object, $property_name );
		$property->setAccessible( true );
		$property->setValue( $object, $value );
		$property->setAccessible( false );
	}

	public function test_update_private_property() {
		$suit = new Suit();
		$this->assertSame( 'private property value', $suit->get_private_property() );

		$this->update_inaccessible_property( $suit, 'private_property', 'new private property value' );
		$this->assertSame( 'new private property value', $suit->get_private_property() );
	}

}