Модульное тестирование(Unit tests) с помощью PHPUnit

Зачем нужны тесты и какие виды тестов должен писать разработчик вы можете узнать здесь.

Модульные тесты главным образом пишутся в качестве хорошей практики, помогающей разработчикам выявлять и исправлять баги, проводить рефакторинг кода и служить в качестве документации для тестируемого программного модуля (программы). Для достижения этих преимуществ модульные тесты в идеале должны охватывать все возможные пути исполнения программы. Один модульный тест обычно покрывает один конкретный путь в одной функции или методе. Однако тестовые методы необязательно должны быть инкапсулированными и независимыми. Часто существуют неявные зависимости между тестовыми методами, скрытые в сценарии реализации теста.

Адриан Кун (Adrian Kuhn) и другие:

Установка PHPUnit и написание первый тест

Для начала нужно установить версию php7.2+ и composer. Затем в проекте устанавливаем phpunit:

composer require --dev phpunit/phpunit

Создаем пример для теста Duck.php:

<?php

class Duck {

	public function say(): string {
		return 'krya-krya';
	}

}

Создаем папку tests и добавляем туда тестируем класс DuckTest.php (по умолчанию PHPUnit смотрит на все файлы в которые заканчиваются на Test.php).

<?php

require_once __DIR__ . '/../Duck.php';

class Krya_Test extends PHPUnitFrameworkTestCase {

	public function test_say() {
		$krya = new Duck();
		$this->assertSame( 'krya-krya', $krya->say() );
	}

}

И запускаем тесты:

vendor/bin/phpunit tests/

Если вы увидели такое сообщение, то все сделано верно.

PHPUnit 9.0.1 by Sebastian Bergmann and contributors.

.     1 / 1 (100%)

Time: 42 ms, Memory: 4.00 MB

OK (1 test, 1 assertion)

Базовые вещи, которые нужно знать:

Фикстуры (Fixture)

Фиксутра — настройка окружения и возврат его в исходное состояние. Звучит страшно, но на самом деле это просто методы, которые позволяют настроить окружение для теста. В классе PHPUnitFrameworkTestCase для этого есть методы:

  • setUp выполняются перед каждым тестом тестового класса;
  • tearDown выполняются после каждого теста тестового класса;
  • setUpBeforeClass — выполняется перед первым тестом в тестовом классе;
  • tearDownAfterClass — выполняется после запуска последнего теста тестового класса.

Пример:

<?php

class FixtureTest extends PHPUnitFrameworkTestCase {

	private $counter;
	
	protected function setUp(): void {
		$this->counter = 0;
		parent::setUp();
	}

	public function test_fixture_1() {
		$this->counter++;
		$this->assertSame( 1, $this->counter );
	}

	public function test_fixture_2() {
		$this->assertSame( 0, $this->counter );
	}

}

Получается в каждом тестируемом методе свойство counter будет равно 0.

Утверждение (Asserts)

Утверждения — это методы класса TestCase, которые помогают проверить тест. Все эти методы начинаются с assert (assertTrue, assertSame, assertClassHasAttribute и т.д.). После выполнения тестов будет показано кол-во выполненных тестов и кол-во выполненных утверждений. В случае неверного утверждения тест считается проваленным.

Тестовые двойники (Заглушки, Stubs, Mocks)

Stubs — объект, поведение которого мы описывает в тесте, но по какой-то причине не можем его вызвать через new. Например в момент тестирования абстрактного класс SomeClass:

<?php
use PHPUnitFrameworkTestCase;

class StubTest extends TestCase
{
    public function testStub()
    {
        $stub = $this->createMock(SomeClass::class);

        $stub->method('doSomething')
             ->willReturn('foo');

        $this->assertSame('foo', $stub->doSomething());
    }
}

В тесте мы создали объект SomeClass и присвоили ему метод doSomething, который при вызове вернет строку «foo».

Mocks — объект, который мы хотим использовать в тестируемом объекте. Например у нас есть класс Duck в конструктор которого должен попасть объект Headdress:

<?php
use PHPUnitFrameworkTestCase;

class MockTest extends TestCase
{
    public function testStub()
    {
        $headdress = $this->createMock(Headdress::class);
        
        $duck = new Duck( $headdress );

        $this->assertSame('krya-krya', $duck->say() );
    }
}

Настройка окружения для всех тестов (Bootstrap)

Для настройки окружения для всех тестов можно создать файл bootstrap.php и объявить там необходимые вещи. Например в этом файле мы можем подключить библиотеки необходимые для тестирования, изменить глобальные и супер-переменные, объявить константы и т.д.

Пример bootstrap.php файла:

define( 'PLUGIN_PATH', __DIR__ '/../' );

require_once PLUGIN_PATH . '/vendor/autoload.php';

Конфигурационный XML-файл

Мы можем настроить выполнение команд с помощью конфигурационного XML-файла, в котором можно изменить стандартные настройки phpunit, указать папку с тестами, путь к бутстап файлу, настроить фильтры и другое.

Пример XML-файла:

<phpunit
        bootstrap="./bootstrap.php"
        colors="true"
>
    <testsuites>
        <testsuite name="Config-example-for-tests">
            <directory suffix=".php">./tests/</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist>
            <directory suffix=".php">../../</directory>
            <exclude>
                <directory>../../src</directory>
                <directory>../../tests</directory>
                <directory>../../vendor</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>

Атрибутами или вложенными тегами к <phpunit> могут быть любые команды, которые есть в phpunit. В нашем случае

vendor/bin/phpunit /tests/ --bootsrap /tests/bootsrap.php --colors --test-suffix=".php" ...

Меняется на:

vendor/bin/phpunit --configuration phpunit.xml

Покрытие тестами (Tests coverage)

С помощью этого инструмента очень легко понять насколько качественно написаны тесты, сколько файлов покрыты тестами и какие строки в них покрыты. Данный инструмент очень сильно помогает отслеживать качество ваших тестов.

Важно!!! Необходимо к вашему php-cli подключить xdebug иначе coverage будет недоступен и вы получите уведомление об отсутствии модуля для тестирования.

Чтобы его использовать достаточно дописать к phpunit —coverage-{type} атрибут. Например очень удобно использовать HTML-формат покрытия:

vendor/bin/phpunit --configuration phpunit.xml --coverage-html coverage

После этого в проекте создается папка coverage и мы можем открыть файл index.html и просмотреть подробную информацию о каждом файле тестирования.

Добавить комментарий

%d такие блоггеры, как: