PHPUnit — Глава 16. Генератор каркаса

Генератор каркаса в PHPUnit это утилита, позволяющая создавать каркасы классов тестов исходя из рабочих классов и наоборот. Его можно установить с помощью следующей команды:

pear install phpunit/PHPUnit_SkeletonGenerator

 Создание каркаса тест класса

  Когда тестируется уже готовый код приходится писать одинаковые фрагменты теста, такие как

public function testMethod()
{
}

Генератор каркасов PHPUnit может помочь в этом. он создаёт шаблон для класса теста, анализируя код существующего класса . 

Пример 16.1. Класс Calculator

<?php
class Calculator
{
    public function add($a, $b)
    {
        return $a + $b;
    }
}
?>

Следующий пример показывает как создать шаблон тестового класса Calculator (см. Пример 16.1, «Класс Calculator»).

phpunit-skelgen --test Calculator
PHPUnit Skeleton Generator 1.0.0 by Sebastian Bergmann.

Wrote skeleton for "CalculatorTest" to "/home/sb/CalculatorTest.php".

  Для каждого метода исходного класса будут созданы незаконченные (incomplete) тест кейсы (см. Глава 9, Incomplete and Skipped Tests ) в созданном генератором классе.

Классы с пространствами имен и генератор каркаса

Когда PHPUnit создает каркас для класса, который объявлен в пространстве имён, необходимо предоставить полное имя класса и путь к файлу исходного класса.

Например, для класса Calculator, который объявлен в пространстве имён project следует вызвать генератор каркаса следующим образом:

phpunit-skelgen --test -- "project\Calculator" Calculator.php
PHPUnit Skeleton Generator 1.0.0 by Sebastian Bergmann.

Wrote skeleton for "project\CalculatorTest" to "/home/sb/CalculatorTest.php".

Ниже представлен вывод запуска тестирования для нового созданного класса:

phpunit --bootstrap Calculator.php --verbose CalculatorTest
PHPUnit 3.7.0 by Sebastian Bergmann.

I

Time: 0 seconds, Memory: 3.50Mb

There was 1 incomplete test:

1) CalculatorTest::testAdd
This test has not been implemented yet.

/home/sb/CalculatorTest.php:38
OK, but incomplete or skipped tests!
Tests: 1, Assertions: 0, Incomplete: 1.

    Используя аннотацию @assert в блоке документации исходного метода можно создать простой, но все же работающий тест вместо незавершённого тест кейса. Пример 16.2, «Класс Calculator c аннотациями @assert» показывает пример использования аннотации. 

Пример 16.2. Класс Calculator c аннотациями @assert

<?php
class Calculator
{
    /**
     * @assert (0, 0) == 0
     * @assert (0, 1) == 1
     * @assert (1, 0) == 1
     * @assert (1, 1) == 2
     */
    public function add($a, $b)
    {
        return $a + $b;
    }
}
?>

Каждый метод исходного класса проверяется на наличие аннотации @assert, и они преобразуются в тестовый код, такой как

    /**
     * Generated from @assert (0, 0) == 0.
     */
    public function testAdd() {
        $o = new Calculator;
        $this->assertEquals(0, $o->add(0, 0));
    }

Ниже представлен пример запуска созданного класса тест кейса.

phpunit --bootstrap Calculator.php --verbose CalculatorTest
PHPUnit 3.7.0 by Sebastian Bergmann.

....

Time: 0 seconds, Memory: 3.50Mb

OK (4 tests, 4 assertions)

Таблица 16.1, «Поддерживаемые варианты аннотации @assert» показывает все возможные варианты аннотации @assert и то как они преобразуются в код теста.

 Таблица 16.1. Поддерживаемые варианты аннотации @assert

АннотацияПреобразуется в
@assert (...) == X assertEquals(X, method(...))
@assert (...) != X assertNotEquals(X, method(...))
@assert (...) === X assertSame(X, method(...))
@assert (...) !== X assertNotSame(X, method(...))
@assert (...) > X assertGreaterThan(X, method(...))
@assert (...) >= X assertGreaterThanOrEqual(X, method(...))
@assert (...) < X assertLessThan(X, method(...))
@assert (...) <= X assertLessThanOrEqual(X, method(...))
@assert (...) throws X @expectedException X

 Создание рабочего класса из класса тест кейса

Когда вы используете Test-Driven Development (см. Глава 12, Test-Driven Development ) и пишете тесты перед тем как писать код, который выполняется тестами, PHPUnit может помочь создать каркасы рабочих классов из классов тест кейсов.

Соглашение подразумевает что тесты для класса Unit реализованы в классе UnitTest. В этом классе генератор ищет все переменные, которые ссылаются на класс Unit и анализирует все методы, вызываемые этими объектами. Например, взгляните на код Пример 16.4, «Сгенерированный каркас класса BowlingGame», который был создан при анализе Пример 16.3, «Класс BowlingGameTest».

 Пример 16.3. Класс BowlingGameTest

<?php
class BowlingGameTest extends PHPUnit_Framework_TestCase
{
    protected $game;

    protected function setUp()
    {
        $this->game = new BowlingGame;
    }

    protected function rollMany($n, $pins)
    {
        for ($i = 0; $i < $n; $i++) {
            $this->game->roll($pins);
        }
    }

    public function testScoreForGutterGameIs0()
    {
        $this->rollMany(20, 0);
        $this->assertEquals(0, $this->game->score());
    }
}
?>

 

phpunit-skelgen --class BowlingGameTest
PHPUnit Skeleton Generator 1.0.0 by Sebastian Bergmann.

Wrote skeleton for "BowlingGame" to "./BowlingGame.php".
 

Пример 16.4. Сгенерированный каркас класса BowlingGame

<?php
/**
 * Generated by PHPUnit_SkeletonGenerator on 2012-01-09 at 16:55:58.
 */
class BowlingGame
{
    /**
     * @todo Implement roll().
     */
    public function roll()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }

    /**
     * @todo Implement score().
     */
    public function score()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }
}
?>

Ниже приведён вывод запуска тестов для созданного класса

phpunit --bootstrap BowlingGame.php BowlingGameTest
PHPUnit 3.7.0 by Sebastian Bergmann.

E

Time: 0 seconds, Memory: 3.50Mb

There was 1 error:

1) BowlingGameTest::testScoreForGutterGameIs0
RuntimeException: Not yet implemented.

/home/sb/BowlingGame.php:13
/home/sb/BowlingGameTest.php:14
/home/sb/BowlingGameTest.php:20

FAILURES!
Tests: 1, Assertions: 0, Errors: 1.

28.03.2017 15:23