@MasterCopipaster

Как замокать приватное свойство в классе phpunit?

Народ помогите, чет словил тупишку, вообщем есть начало такого класса
class Relay implements ConsumerInterface
{
    /**
     * @var MemcachedAdapter
     */
    private $memory;

    public function __construct()
    {
        $client = MemcachedAdapter::createConnection('memcached://localhost');
        $this->memory = new MemcachedAdapter($client, $namespace = '',$defaultLifetime = 0);

Мне надо написать к нему тест, для этого мне надо замокать $this->memory
Как написать моку я знаю, но не знаю как подменить ее в приватном свойстве.
Короче как подменить $this->memory что бы там лежала моя мока?
  • Вопрос задан
  • 489 просмотров
Решения вопроса 1
Maksclub
@Maksclub
maksfedorov.ru
Имитация вашего объекта:
class Relay
{
    private $privateProperty;

    public function __construct()
    {
        $this->privateProperty = new \stdClass();
    }

    // метод, который работает с приватным свойством
    public function call()
    {
        return $this->privateProperty;
    }
}


Способ 1: Нативный PhpUnit + Reflection API
use PHPUnit\Framework\TestCase;

class RelayTest extends TestCase
{
    public function testCall(): void
    {
        $reflectionClass = new \ReflectionClass(Relay::class);
        $reflectionProperty = $reflectionClass->getProperty('privateProperty');
        $reflectionProperty->setAccessible(true);

        // создаем наш объект БЕЗ конструктора
        $relay = $reflectionClass->newInstanceWithoutConstructor();

        // Меняем свойство и вызываем метод, работающий с этим приватным полем
        $reflectionProperty->setValue($relay, 1111);
        self::assertEquals(1111, $relay->call());

        // Меняем свойство и вызываем метод, работающий с этим приватным полем
        $reflectionProperty->setValue($relay, 'aaaa');
        self::assertEquals('aaaa', $relay->call());
    }
}


Способ 2: Через Codeception Stub
class RelayTest extends TestCase
    public function testCall(): void
    {
        /** @var Example $stub */
        $stub = Stub::make(Relay::class, [
            'privateProperty' => 1111,
        ]);
        self::assertEquals(1111, $stub->call());

        $stub = Stub::make(Relay::class, [
            'privateProperty' => 'aaaa',
        ]);
        self::assertEquals('aaaa', $stub->call());
    }
}

Отступления и полезные советы:
  • Почему-то стандартный, давно используемый мною, способ с инъекцией в мок приватного филда не зашел и выдавал null всегда.
  • Юзайте Inversion of Control Principle, например инъекцию зависимости через конструктор или инъекцию через метод с присвоением в конструкторе NullObject. Оба способа будут хороши для тестирования.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы