Блог/Наборы данных в PHPUnit

Использование наборов данных в PHPUnit

Автор: Кудашев Сергей

В предновогодней суете хотелось бы в очередной раз коснуться вопроса разработки с PHPUnit. На этот раз речь пойдет об использовании наборов данных (на языке PHPUnit они называются дата провайдеры) для автоматических тестов. Почему захотелось написать именно про наборы, потому что это не часто используемая техника позволяет существенно сократить код тестов и сделать их более наглядными.

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

Фреймворк PHPUnit позволяет передавать наборы данных в тестовые методы. Такой набор данных называется Data Provider и должен генерировать публичным методом и представлять из себя либо массив массивов, либо объект, реализующий Iterator интерфейс. Данные генерируемые этим методом мы будем передавать на тестовый метод.

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

class StrStrip
{
	public function process($text = '', $mode = 'soft') {
		if(empty($text)) return $text;

		if($mode === 'soft') {
			$post = ['/ {2,}/', '/\t{1,}/'];
		} else {
			$post = ['/\s+/'];
		}
		$repl = [' ', ' ', ' '];
		return preg_replace($post, $repl, $text);
	}
}

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

$this->assertEquals("тестовый набор текст", $this->test->process("тестовый набор текст", "soft"));
$this->assertEquals("тестовый набор текст", $this->test->process("тестовый набор\t\t текст", "soft"));
$this->assertEquals("тестовый набор текст", $this->test->process("тестовый набор\t \tтекст", "soft"));

Для его использования необходимо написать директиву PHPDoc @dataProvider перед объявлением тестового метода, после чего мы можем использовать возвращаемые данные дата провайдера в качестве входящих аргументов метода.

<?php

require 'StrStrip.php';

class testTest extends PHPUnit_Framework_TestCase
{
	protected $test;

	public function setUp()
	{
		parent::setUp(); // TODO: Change the autogenerated stub
		$this->test = new StrStrip();
	}

	public function tearDown()
	{
		parent::tearDown(); // TODO: Change the autogenerated stub
		$this->test = null;
	}

	/** @return array ['input', 'expected'] */
	public function stripProvider()
	{
		return [
			['soft', "тестовый набор текст", "тестовый набор текст"],
			['soft', "тестовый набор\tтекст", "тестовый набор текст"],
			['soft', "тестовый набор текст", "тестовый набор текст"],
			['soft', "тестовый набор\t\t текст", "тестовый набор текст"],
			['soft', "тестовый набор \t\t текст", "тестовый набор текст"],
			['soft', "тестовый набор\t \tтекст", "тестовый набор текст"],
			['hard', "тестовый набор\t\t текст", "тестовый набор текст"],
			['hard', "тестовый набор\t \tтекст", "тестовый набор текст"],
		];
	}

	/** @dataProvider stripProvider */
	public function testStrStripper($mode, $text, $expected)
	{
		$this->assertEquals($expected, $this->test->process($text, $mode));
	}
}

При выполнении тестов PHPUnit сам передаст данные на вход нашему методу и обработает данные. Таким образом мы получаем более наглядный и простой инструмент работы с большими объемами тестовых данных. Рекомендую использовать в повседневной разработке :)

Комментарии (0)