Модульное тестирование (Рейтинг: +3)

Печать RSS
Введение
Модульное тестирование это то, чем вы пользуетесь постоянно во время разработки и даже не замечаете этого. В процессе написания кода вы по многу раз запускаете его, чтобы убедится в том, что он работает ожидаемым образом. Так почему бы не автоматизировать этот процесс? Для этих целей применяется "Автоматизированное модульное тестирование" (АМТ) и "Модульные тесты".

АМТ решает следующие важные задачи:
* Позволяет выявить ошибку на раннем этапе разработки, до того, как код уйдет в работу. Своевременное выявление ошибки так же упрощает ее локализацию и исправление
* Позволяет быстро удостоверится в том, что вносимые в систему изменения не поломали старый код
* Облегчает процесс изучения системы новыми разработчиками

Но не следует забывать, что АМТ, как и код системы, требует поддержки и модернизации, что отнимает время у разработчика.

Фреймворк xUnit, часто применяется для создания АМТ во многих языках программирования. Для PHP так же существует его разновидность - PHPUnit. Работу с ним я и опишу в данной статье.

Установка PHPUnit
Для установки фреймворка PHPUnit воспользуйтесь следующей командой (для Linux систем):
wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/local/bin/phpunit

Эта команда загрузит фреймворк, распространяемый в виде PHAR-пакета, предоставит ему права на выполнение и переместит его в соответствующий каталог.

Основы модульного тестирования
АМТ представляет собой множество классов, каждый из которых тестирует конкретную логику системы. Все эти классы должны наследоваться от базового класса PHPUnit_Framework_TestCase и содержать один или более методов, имя которых начинается с test.

Рассмотрим пример создания собственного класса для автоматизированного модульного тестирования. Представим что у нас есть следующий класс, реализующий простой стек:
class MyStack implements Countable{
  private $store;

  public function __construct(){
    $this->store = [];
  }

  public function push($value){
    array_push($this->store, $value);
  }

  public function pop(){
    return array_pop($this->store);
  }

  public function count(){
    return count($this->store);
  }
}

Для тестирования этого класса мы используем следующий модульный тест:

class MyStackTest extends PHPUnit_Framework_TestCase{
  public function testConstruct(){
    $stack = new MyStack();

    $this->assertEquals(0, count($stack));
  }

  public function testPush(){
    $stack = new MyStack();

    $stack->push(5);

    $this->assertEquals(1, count($stack));
  }

  public function testPop(){
    $stack = new MyStack();

    $stack->push(5);

    $this->assertEquals(5, $stack->pop());
    $this->assertEquals(0, count($stack));
  }
}

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

Для запуска этого теста выполните команду:
phpunit MyStackTest.php

Шаблоны тестирования
Применяя АМТ старайтесь использовать следующие шаблоны:
* Структурируйте тесты - помните, что любой тест всегда состоит из предусловий, вызова и проверки постусловий
public function testPop(){
  // Предусловия
  $stack = new MyStack();

  // Вызов
  $stack->push(5);

  // Проверка постусловий
  $this->assertEquals(5, $stack->pop());
  $this->assertEquals(0, count($stack));
}
* Понятные имена для тестов - старайтесь именовать методы теста так, чтобы было понятно, что они проверяют. Так, метод testPop можно было бы переименовать в testPop_shouldSliceCurrentStackValue
* Применение фабрик в тесте - если в одном тесте вы часто создаете один и тот же объект, выделите его состояние в метод-фабрику. Так, код $stack = new MyStack можно было бы обернуть в метод createStack и использовать в тестах следующим образом: $stack = $this->createStack()
* Не проверяйте с помощью тестов внутреннюю логику класса, только постусловия. Другими словами тесту не нужно знать как именно работает класс, достаточно проверить, что при некоторых предусловиях и вызове всегда достигаются данные постусловия
* Не повторяйтесь. Как и при разработке приложения, старайтесь не заниматься "программированием через копипаст" во время написания тестов. Помните, что вы должны их сопровождать, а повторяющийся код сделает сопровождение сложным
* Пишите тесты так, чтобы после их прочтения было понятно, что делает тестируемый класс. Запомните - тесты это особая документация, отвечающая на вопрос: "Что должен и что не должен делать класс"

Послесловие
Я намерено упростил статью, выбросив из нее множество важных деталей, таких как Mock-объекты и тестирование исключений. Если вас заинтересовала тема модульного тестирования, обязательно обратитесь к следующей литературе:
* http://www.ozon.ru/context/detail/id/1501671/
* http://www.ozon.ru/context/detail/id/4127815/
Добавил:
Рейтинг: +3
Просмотры: 1429
Комментарии (9) »