@Evdokim001
PHP & WordPress developer

Как правильно писать тесты PHPUnit под ООП?

В плане функциональных языков, тесты под них кажется легко написать, ведь каждую функцию можно вызвать напрямую.

Когда я пишу классы PHP, то оставляю открытыми(public) только пару методов из 5-10. В таком случае я могу проверять только результат этих нескольких методов в то время как большая часть остается непройденной тестами. Как проверять результат методов private и protected без изменения открытости методов? Возможно само построение класса неверное...

Расскажите пожалуйста, каких правил вы придерживаетесь для создания классов и как создаете тесты под них чтобы проверить все максимально хорошо?

Спасибо
  • Вопрос задан
  • 98 просмотров
Решения вопроса 1
Вам не надо тестировать приватные методы.
Но как же тогда быть, вы скажете?
Публичные методы используют эти приватные методы, так и проходит тестирование.
Из этого вытекает, что класс должен быть небольшим и выполнять только одну задачу. Поэтому его приватные методы будут всегда задействованы при тестировании публичных.
Но вы скажете, что у вас там в публичных методах обращения к базе данных и внешним API, как же тут быть?
А быть тут просто: все зависимости вашего класса должны включаться в качестве аргументов конструктора, и через использование интерфейсов в аргументах. (Dependency Injection)
Таким образом в тесте все зависимости класса заменяются теми же моками, и вы легко тестируете не просто сферического корня в вакууме (приватный метод), а именно то, что и нужно тестировать: функциональность самого класса, а не его частей, потому что в OOP именно класс является как бы атомом функционала.
Но... если вам всё же таки очень надо, то можно это сделать при помощи рефлексии:
Хорошей практикой является использовать всегда protected вместо private.
Пишете себе такую вот утилиту:
class PHPUnitUtil
{
  public static function callMethod($obj, $name, array $args) {
        $class = new \ReflectionClass($obj);
        $method = $class->getMethod($name);
        // $method->setAccessible(true); // если PHP старше 8.1.0
        return $method->invokeArgs($obj, $args);
    }
}


И используете ее в тестах
$returnVal = PHPUnitUtil::callMethod(
                $this->object,
                '_nameOfProtectedMethod', 
                array($arg1, $arg2)
             );


Есть ещё вариант.
// Оригинальный класс
class Foo {
  protected function stuff() {
    // secret stuff, you want to test
  }
}

// Класс для тестов
class SubFoo extends Foo {
  public function exposedStuff() {
    return $this->stuff();
  }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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