PHPUnit – это система для юнит-тестирования приложений, написанных на языке PHP. Под "юнит" понимаются небольшие блоки кода, например отдельные методы класса. Т.е. можно протестировать метод на работоспособность в автоматическом режиме. Когда приложение достаточно большое, содержащее много классов, методов и тем более если планируется дальнейшее его расширение стоит заняться тестированием и в этом поможет PHPUnit. Он представляет собой отдельную библиотеку классов, которые нужно подключить при создании своего теста. Подробнее читайте на официальном сайте https://phpunit.ru

В предыдущей статье я описал способы установки PHPUnit.

Создание теста заключается в создании отдельного файла с классом, который будет отвечать за тестирование определенного класса приложения.

Имя тестирующего класса образуется добавлением приставки Test к имени тестируемого класса. Например, вы тестируете класс User, значит имя тестирующего — UserTest. Название файла с классом должно совпадать с названием класса + расширение .php т.е. UserTest.php

Имена тестирующих методов всегда должны начинаться с “test” (например testNewUserReturnTrue). Методы должны быть публичными.
Тестирующие методы не принимают параметров (кроме провайдеров данных). Вы должны писать тестирующие методы максимально независимыми и самодостаточными.

В примерах, часто, подключается тестируемый файл таким образом:
require_once dirname(__FILE__).'/../User.php';
На самом деле в реальных проектах, использующих пространства имен, подключение должно осуществляться автоматически, обычно с помощью автозагрузчика Composer. Конечно для этого нужно следовать стандартам psr при подключении классов проекта.


Самый простой пример.

Файл app\Model.php:
<?php
namespace app;
class Model {
    public function check() {
        //
        return true;
 }
}

Файл test\ModelTest.php:
<?php
namespace tests;
use PHPUnit\Framework\TestCase;
use app\Model;
class ModelTest extends TestCase
{
 public function testCheckTrue(){
    $model = new Model();
    $this->assertTrue($model->check());
 }
}
В данном примере мы тестируем метод check() класса Model на то, что в результате своей работы он вернет true.
В строке
$this->assertTrue($model->check());
используется метод фреймворка для тестирования PHPUnit assertTrue(), который ожидает от вызова метода check() возвращаемое значение true. Если ожидание подтверждается, то тест будет пройден успешно.

В PHPUnit множество таких проверочных методов и все они начинаются с assert*. Перечислю основные из них:
AssertTrue/AssertFalse - Проверка переданных значений на равенство true/false
AssertEquals - Проверка переданных значений на равенство
AssertGreaterThan - Сравнивает две переменные (есть так же LessThan, GreaterThanOrEqual, and LessThanOrEqual)
AssertContains - Содержит ли переданная переменная заданное значение
assertInternalType (было AssertType) - Проверка типа переменной (string, integer…)
assertInstanceOf - Проверка типа переменной (объекты)
AssertNull - Проверка на равенство null
AssertFileExists - Проверка существования файла
AssertRegExp - Проверка по регулярному выражению

остальные методы и примеры использования можно посмотреть тут в левой колонке, в графе A. Assertions.

Запуск тестов.
Тесты запускаются в командной строке.
- из папки текущего проекта:
phpunit tests
запуск отдельного файла тестов:
phpunit tests\ModelTest
или
phpunit tests\ModelTest.php

- из любого места (указываем полный путь):
phpunit W:\domains\test.loc\tests\ModelTest.php

Если PHPUnit устанавливали с помощью Composer, то по-умолчанию запускать так:
vendor/bin/phpunit tests
Но лучше создать файл phpunit.bat и phpunit.xml чтобы запускать тестирование одной командой:
phpunit



Про создание файла phpunit.bat можно прочитать в предыдущей статье, а phpunit.xml представляет из себя конфигурационный файл, откуда PHPUnit сможет брать данные, чтобы не приходилось их прописывать в командной строке. Создадим данный файл в корне проекта и пропишем там:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true">
    <testsuites>
        <testsuite>
            <directory>tests/</directory>
        </testsuite>
    </testsuites>
</phpunit>
тут мы указали, что тесты хранятся в папке tests, а заодно подсветили вывод результатов выполнения тестов в командной строке.
Данный файл можно так же создать автоматически командой
phpunit --generate-configuration
Будет предложено выбрать соответствующие каталоги или нажать «Enter» для значений по-умолчанию.

Таки образом, настроив PHPUnit вы сможете запускать тесты простой командой: phpunit

При выполнении тестирования, для каждого тестового прогона, РНРUnit framework, в командной строке выводит один символ, указывающий на прогресс выполнения тестирование PHP кода:
. Печатается, когда тест завершается успешно.
F Печатается, когда утверждение терпит неудачу при выполнении тестового метода.
E Печатается, когда возникают ошибки при выполнении тестового метода.
R Печатается, когда тест был отмечен как рискованный (см в следующих статьях).
S Печатается, когда тест был пропущен (см в следующих статьях).
I Печатается, когда тест помечается как неполный или еще не реализован (см в следующих статьях).

При выполнении нашего примера, в консоли должно отобразиться:



Пример 2.




В данном примере я не использую автозагрузчик классов. Будем считать, что РНРUnit мы установили вручную.

Файл User.php:
<?php
class User
{
    public function getPassword(array $user)
    {
        if(isset($user['login'])){
        $user['password'] = uniqid($user['login']);
        return $user;
        }
    return false;  
    }
}
Метод getPassword() получает массив текущего пользователя ($user) и на основе его логина создает временный пароль дополняя массив $user новым элементом - 'password'.

Тест проверяющий наличие элемента с ключем 'password' в массиве $user, который должен вернуть метод getPassword() после выполнения.
Файл tests\UserTest.php:
<?php
require_once dirname(__FILE__).'/../User.php';
use PHPUnit\Framework\TestCase;
class UserTest extends TestCase
{
    public function testGetPassword()
    {
        $obj = new User();
        $user['login'] = 'login';
        $this->assertArrayHasKey('password', $obj->getPassword($user));
    }
}
для тестирования передаем методу getPassword() массив $user с необходимым элементом 'login' и рассчитываем что в возвращаемом им результате (массиве) будет элемент с ключем 'password'.


РНРUnit использует несколько вспомогательных методов. В своих примерах я создавал объект тестируемого класса непосредственно в тестируемом методе, например:
$obj = new User();
Но в классе теста, как правило, есть несколько тестовых методов. Таким образом неправильно было бы дублировать код, а именно создавать объект тестируемого класса в каждом методе. В данном случае удобно использовать метод setUp(), который выполняется перед каждым тестирующим методом. Объект нужного класса создаем в нем, например:
class MyClassTest{
    protected $user;
     protected function setUp() {
      $this->user = new User();
     }
...
дальше обращаемся к методу объекту из любого тестирующего метода:
$this->user;
Есть так же метод tearDown(), который выполняется уже после выполнения тестирующего метода.

Нужно учесть, что при использовании метода setUp(), объект будет создаваться перед каждым тестом, что нужно не всегда. Это может понадобиться если тесты изменяют свойства объекта, а он нужен в первозданном виде. В противном случае стоит использовать статический метод setUpBeforeClass() для разового создания и сохранения объекта в статичном свойстве, например:
static $user; //объект нового пользователя

public static function setUpBeforeClass()
{
 self::$user = new User();
}
Метод setUpBeforeClass() выполняется только раз перед созданием объекта тестирующего класса.

Получить объект в нужном методе:
static::$user
Так же существует статический метод tearDownAfterClass() который выполнится после завершения работы всех тестов класса.


Данная статья является одной из серии статей про фреймворк для тестирования PHPUnit. Читайте так же: