Какова предпочтительная структура модульного тестирования для Perl?

Я как бы новичок в Perl, и мне интересно, есть ли предпочтительная модульная система тестирования?

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

Ответ 1

У Perl есть набор мощных инструментов для тестирования, которые поставляются вместе с ним! Ядро Perl имеет несколько десятков тысяч автоматических проверок для него, и по большей части все они используют эти стандартные платформы Perl. Все они связаны друг с другом, используя TAP - Протокол Test Anything.

Стандартный способ создания тестов TAP в Perl - это использование Test::More семейства пакетов, в том числе Test::Simple для начала работы. Вот краткий пример:

use 5.012;
use warnings;

use Test::More tests => 3;

my $foo = 5;
my $bar = 6;

ok $foo == 5, 'Foo was assigned 5.';
ok $bar == 6, 'Bar was assigned 6.';
ok $foo + $bar == 11, 'Addition works correctly.';

И выход будет:

ok 1 - Foo was assigned 5.
ok 2 - Bar was assigned 6.
ok 3 - Addition works correctly.

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

Как только вы пройдете этот шаг, Test:: More имеет большое количество других функций, чтобы упростить тестирование других вещей (сравнение строк, регулярных выражений, глубокая структура), а там Test::Harness назад, что позволит вам тестировать большие группы отдельных тестовых скриптов вместе.

Кроме того, как отмечалось в Schwern, почти все современные модули Test:: работают вместе. Это означает, что вы можете использовать Test::Class (как указано Markus) со всеми замечательными модулями, перечисленными в rjh . Фактически, поскольку Test::Builder - инструмент, который Test::More и другие встроены (и в настоящее время поддерживается Schwern... thanks Schwern!) - вы можете при необходимости создать свои собственные тестовые подпрограммы с нуля, которые будут работать со всеми другими тестовыми платформами. Это само по себе делает систему Perl TAP одной из самых приятных на мой взгляд: все работает сообща, каждый использует один и тот же инструмент, и вы можете добавить к структуре, чтобы удовлетворить ваши потребности, при этом очень немного дополнительной работы.

Ответ 2

Наиболее популярная тестовая среда "perl" - это формат результатов теста, известный как TAP (Test Anything Protocol), который представляет собой набор строк, которые выглядят следующим образом:

ok 1 - Imported correctly
ok 2 - foo() takes two arguments
not ok 3 - foo() throws an error if passed no arguments

Любой script, который может генерировать эти значения строк как тест Perl. Вы можете использовать Test::More для создания TAP для различных условий - проверки, равна ли переменная значению, проверять правильность импорта модуля или если две структуры (массивы/хэши) идентичны. Но в истинном духе Perl существует не один способ сделать это, и есть другие подходы (например, Test::Class, что немного напоминает JUnit!)

Простой пример теста script (обычно они заканчиваются на .t, например foo.t)

use strict;
use warnings;
use Test::More tests => 3;  # Tell Test::More you intend to do 3 tests

my $foo = 3;
ok(defined $foo, 'foo is defined');
is($foo, 3, 'foo is 3');
$foo++;
is($foo, 4, 'incremented foo');

Вы можете использовать Test::Harness (обычно вызываемый как prove из оболочки) для последовательного запуска серии тестов и получения краткое изложение которого прошло или не удалось.

Test:: More также может выполнять некоторые более сложные вещи, такие как тесты меток как TODO (не ожидайте, что они пройдут, но запустите их на всякий случай) или SKIP (эти тесты разбиты/опциональны, не запускаются их). Вы можете объявить количество тестов, которые вы ожидаете запустить, поэтому, если ваш тест script умирает на полпути, это можно обнаружить.

Как только вы начнете выполнять более сложное тестирование, вы можете найти некоторые другие модули CPAN полезными - вот несколько примеров, но их много (много):

Test::Exception - проверьте, что ваш код выдает ошибку/не вызывает никаких ошибок
Test::Warn - проверьте, что ваш код выполняет/не генерирует предупреждения
Test::Deep - глубоко сравнивать объекты. Они не обязательно должны быть одинаковыми - вы можете игнорировать порядок массивов, использовать регулярные выражения, игнорировать классы объектов и т.д.
Test::Pod - убедитесь, что ваш script имеет POD (документация) и что он действителен Test:: Pod:: Coverage - убедитесь, что ваши POD-документы все методы/функции в ваших модулях
Test::DBUnit - тестирование взаимодействия с базами данных
Test::MockObject - сделать объекты, которые притворяются, чтобы контролировать среду ваших тестов

Ответ 4

Если вы практикуете TDD, вы заметите, что ваш набор модульных тестов меняет LOT. Test::Class следует шаблонам xUnit (http://en.wikipedia.org/wiki/XUnit).

Для меня основным преимуществом xUnit является инкапсуляция каждого теста в методы. Структура называет каждое утверждение по имени тестового метода и добавляет возможность запуска методов настройки и удаления до и после каждого теста.

Я также пробовал использовать "perl-ish" для модульного тестирования (просто используя Test:: More), но я нахожу это своего рода старомодным и громоздким.

Ответ 5

Некоторые антирекомендации могут быть в порядке:

Анти-рекомендация:

НЕ используйте семейство тестовых пакетов Test::Unit для Perl, например Test::Unit::Assert и Test::Unit::TestCases.

Причина: Test::Unit кажется, что он оставлен.

Test:: Unit, Test:: Unit:: TestCases, Test:: Unit:: Assert work, довольно хорошо (когда я использовал их 2015-2016). Test:: Unit предположительно не интегрирован с Perl Test Anything Protocol (TAP), хотя я нашел, что это легко исправить.

Но Test:: Unit разочаровывает, так как многие другие тестовые пакеты Perl, в основном построенные с использованием Test:: Builder, такие как Test:: More, Test:: Most, Test:: Exception, Test:: Differences, Test:: Deep, Test:: Warn и т.д. НЕ МОГУТ взаимодействовать с объектно-ориентированным тестом тестирования Test:: Unit.

Вы можете смешать тесты Test:: Unit и Test:: Builder после того, как вы адаптировали Test:: Unit для работы с Test:: More и TAP; но хорошие возможности этих других пакетов недоступны для расширения OO. Это в значительной степени причина использования теста стиля xUnit в любом случае.

Предположительно CPAN Test::Class позволяет "легко создавать тестовые классы в стиле xUnit/JUnit", но я не уверен, что могу это порекомендовать. Это, конечно, не похоже на xUnit для меня - не OO, идиосинкратические имена типа is(VAL1,VAL2,TESTNAME) вместо имен стиля xUnit, таких как $test_object->assert_equals(VAL1,VAL2,TEST_ERR_MSG). Test:: Class имеет приятную особенность автоматического обнаружения всех тестов, аннотированных: Тест, сопоставимый с xUnit и TEST:: Unit:: TestCase подход к использованию интроспекции для запуска всех функций с именем test _ *.

Однако базовый пакет Test::Builder является объектно-ориентированным и, следовательно, гораздо более стильным стилем xUnit. Не отпугивайте имя - это не factory, это в основном набор с методами тестирования assert. Хотя большинство людей наследует его, вы можете называть его напрямую, если хотите, например. $test_object->is(VAL1,VAL2,TESTNAME), и часто вы можете использовать вызовы Test:: Builder для работы с ограничениями процедурных пакетов, таких как Test:: More, которые построены поверх Test:: Builder - например, для установки уровня вызова, на котором сообщается об ошибке.

Test:: Builder обычно используется в стиле singleton, но вы можете создавать несколько объектов. Я не уверен, будут ли они вести себя так, как можно было бы ожидать от теста семейства xUnit.

До сих пор простой способ обойти ограничения, такие как тесты Perl TAP, используют TEST_NAMES, для каждого утверждения, без иерархии, и не различая TEST_NAMES от TEST_ERROR_MESSAGES. (Уровень отчетности Err помогает с этим недостатком.)

Возможно создание адаптера, делающего тесты Test:: Builder и TAP более ориентированными на объекты, так что вы можете переустанавливать что-то другое, кроме TAP (которое записывает более полезную информацию, чем TAP - предположительно, как ANT XML протокол). Я думаю, что для адаптации имен и/или отсутствующих понятий будет либо включать в Test:: Builder, либо интроспекцию.