Сборка Perl, модульное тестирование, покрытие кода: полный рабочий пример

85

Большинство ответов Stackoverflow, которые я нашел в отношении процесса сборки Perl и модульного тестирования и покрытия кода, просто указывают мне CPAN для документации. Нет абсолютно ничего плохого в том, чтобы указывать на модули CPAN, потому что там, где должна находиться полная документация. Тем не менее, у меня были проблемы с поиском полных примеров рабочих кодов.

Я искал по всему Интернету фактические примеры рабочих кодов, которые я могу загрузить или вставить в свою среду IDE, например, ваш типичный исходный код примера "Hello World", но пример, демонстрирующий процесс сборки с помощью блока тестирования и анализа покрытия кода. Есть ли у кого-нибудь небольшой пример полного рабочего проекта, демонстрирующего эти технологии и процессы?

(У меня есть небольшой рабочий пример, и я отвечу на его собственный вопрос, но есть, вероятно, другие пользователи SO, у которых есть лучшие примеры, чем те, которые я придумал.)

Теги:
unit-testing
code-coverage
build-automation
build-process

5 ответов

101
Лучший ответ

Мне потребовалось некоторое время, и мне также потребовались небольшие фрагменты из разных источников и их таяние вместе, но я думаю, что у меня есть небольшой рабочий пример, который достаточно демонстрирует новичкам Perl процесс сборки Perl, включая модульное тестирование и анализ покрытия кода и отчетность. (Я использую ActiveState ActivePerl v5.10.0 на ПК с Windows XP Pro, Module:: Build, Test:: More, Devel:: Обложка)

Начните с каталога для своего проекта Perl, а затем создайте каталог "lib" и "t" в каталоге вашего проекта:

HelloPerlBuildWorld
        |
        |----------> lib
        |
        |----------> t

В каталоге "lib" создайте текстовый файл с именем "HelloPerlBuildWorld.pm". Этот файл является вашим модулем Perl, который вы будете строить и тестировать. Вставьте следующий файл в этот файл:

use strict;
use warnings;
package HelloPerlBuildWorld;

$HelloPerlBuildWorld::VERSION = '0.1';

sub hello {
   return "Hello, Perl Build World!";
}

sub bye {
   return "Goodbye, cruel world!";
}

sub repeat {
   return 1;
}

sub argumentTest {
    my ($booleanArg) = @_;

    if (!defined($booleanArg)) {
        return "null";
    }
    elsif ($booleanArg eq "false") {
        return "false";
    }
    elsif ($booleanArg eq "true") {
        return "true";
    }
    else {
        return "unknown";
    }

   return "Unreachable code: cannot be covered";
}

1;

В каталоге "t" создайте текстовый файл с именем "HelloPerlBuildWorld.t". Этот файл является вашим unit test script, который попытается полностью протестировать ваш модуль Perl выше. Вставьте следующий файл в этот файл:

use strict;
use warnings;
use Test::More qw(no_plan);

# Verify module can be included via "use" pragma
BEGIN { use_ok('HelloPerlBuildWorld') };

# Verify module can be included via "require" pragma
require_ok( 'HelloPerlBuildWorld' );

# Test hello() routine using a regular expression
my $helloCall = HelloPerlBuildWorld::hello();
like($helloCall, qr/Hello, .*World/, "hello() RE test");

# Test hello_message() routine using a got/expected routine
is($helloCall, "Hello, Perl Build World!", "hello() IS test");

# Do not test bye() routine

# Test repeat() routine using a got/expected routine
for (my $ctr=1; $ctr<=10; $ctr++) {
    my $repeatCall = HelloPerlBuildWorld::repeat();
    is($repeatCall, 1, "repeat() IS test");
}

# Test argumentTest() 
my $argumentTestCall1 = HelloPerlBuildWorld::argumentTest();
is($argumentTestCall1, "null", "argumentTest() IS null test");

# Test argumentTest("true") 
my $argumentTestCall2 = HelloPerlBuildWorld::argumentTest("true");
is($argumentTestCall2, "true", "argumentTest() IS true test");

# Test argumentTest("false") 
my $argumentTestCall3 = HelloPerlBuildWorld::argumentTest("false");
is($argumentTestCall3, "false", "argumentTest() IS false test");

# Test argumentTest(123) 
my $argumentTestCall4 = HelloPerlBuildWorld::argumentTest(123);
is($argumentTestCall4, "unknown", "argumentTest() IS unknown test");

Теперь создайте резервную копию в своем каталоге проектов верхнего уровня, создайте текстовый файл с именем "Build.PL". Этот файл создаст скрипты сборки, которые вы будете использовать позже. Вставьте следующий файл в этот файл:

use strict;
use warnings;
use Module::Build;

my $builder = Module::Build->new(
    module_name         => 'HelloPerlBuildWorld',
    license             => 'perl',
    dist_abstract       => 'HelloPerlBuildWorld short description',
    dist_author         => 'Author Name <[email protected]>',
    build_requires => {
        'Test::More' => '0.10',
    },
);

$builder->create_build_script();

Чтобы все файлы вам нужны. Теперь из командной строки в каталоге проекта верхнего уровня введите следующую команду:

perl Build.PL

Вы увидите что-то похожее на следующее:

Checking prerequisites...
Looks good

Creating new 'Build' script for 'HelloPerlBuildWorld' version '0.1'

Теперь вы должны иметь возможность запускать свои модульные тесты с помощью следующей команды:

Build test

И посмотрите что-то похожее на это:

Copying lib\HelloPerlBuildWorld.pm -> blib\lib\HelloPerlBuildWorld.pm
t\HelloPerlBuildWorld....ok
All tests successful.
Files=1, Tests=18,  0 wallclock secs ( 0.00 cusr +  0.00 csys =  0.00 CPU)

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

Build testcover

И вы увидите что-то по порядку:

t\HelloPerlBuildWorld....ok
All tests successful.
Files=1, Tests=18, 12 wallclock secs ( 0.00 cusr +  0.00 csys =  0.00 CPU)
cover
Reading database from D:/Documents and Settings/LeuchKW/workspace/HelloPerlBuildWorld/cover_db


----------------------------------- ------ ------ ------ ------ ------ ------
File                                  stmt   bran   cond    sub   time  total
----------------------------------- ------ ------ ------ ------ ------ ------
D:/Perl/lib/ActivePerl/Config.pm       0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/ActiveState/Path.pm        0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/AutoLoader.pm              0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/B.pm                      18.6   16.7   13.3   19.2   96.4   17.6
 ...
[SNIP]
 ...
D:/Perl/lib/re.pm                      0.0    0.0    0.0    0.0    n/a    0.0
D:/Perl/lib/strict.pm                 84.6   50.0   50.0  100.0    0.0   73.1
D:/Perl/lib/vars.pm                   44.4   36.4    0.0  100.0    0.0   36.2
D:/Perl/lib/warnings.pm               15.3   12.1    0.0   11.1    0.0   12.0
D:/Perl/lib/warnings/register.pm       0.0    0.0    n/a    0.0    n/a    0.0
blib/lib/HelloPerlBuildWorld.pm       87.5  100.0    n/a   83.3    0.0   89.3
Total                                  9.9    4.6    2.8   11.3  100.0    7.6
----------------------------------- ------ ------ ------ ------ ------ ------


Writing HTML output to D:/Documents and Settings/LeuchKW/workspace/HelloPerlBuildWorld/cover_db/coverage.html ...
done.

(Кто-нибудь, пожалуйста, сообщите мне, как настроить Cover, чтобы игнорировать все библиотеки Perl, кроме как и просто отчитываться обо мне в моем единственном файле, который я написал. Я не мог заставить фильтрацию Cover работать в соответствии с документацией CPAN!)

Теперь, если вы обновите свой каталог верхнего уровня, вы увидите новый подкаталог под названием "cover_db". Перейдите в этот каталог и дважды щелкните файл "coverage.html", чтобы открыть отчет о охвате кода в своем любимом веб-браузере. Он дает вам хороший отчет с гипертекстом с цветовой кодировкой, в котором вы можете щелкнуть по имени вашего файла и просмотреть подробный отчет о состоянии, ветке, состоянии, подпрограмме для вашего модуля Perl прямо там, в отчете рядом с фактическим исходным кодом. В этом отчете вы можете видеть, что мы вообще не рассматривали подпрограмму "bye()", а также имеется недостижимая строка кода, которая не была покрыта, как мы ожидали.

моментальный снимок отчета о покрытии кода http://www.leucht.com/images/CodeCoverageExample.jpg

Еще одна вещь, которую вы можете сделать, чтобы помочь автоматизировать этот процесс в вашей среде IDE, - это сделать еще несколько файлов типа "Build.PL", которые явно выполняют некоторые из целей сборки, которые мы делали выше вручную из командной строки. Например, я использую файл "BuildTest.PL" со следующим содержимым:

use strict;
use warnings;
use Module::Build;

my $build = Module::Build->resume (
  properties => {
    config_dir => '_build',
  },
);

$build->dispatch('build');
$build->dispatch('test');

Затем я настроил свою IDE для выполнения этого файла (через "perl BuiltTest.PL" ) одним щелчком мыши, и он автоматически запускает мой unit test код из IDE вместо того, чтобы я делал это вручную из командной строки. Замените "отправку (" тест ")" на "отправку (" testcover ")" для автоматического выполнения покрытия кода. Введите "Сборка справки" для получения полного списка целей сборки, доступных из модуля:: Build.

  • 1
    Ваша идея настроить BuiltTest.PL не звучит мне хорошо. Почему вы не можете просто написать скрипт, который выполняет Build build а затем Build test ?
  • 2
    Леон, ты предлагаешь Perl-скрипт, который делает вызовы командной строки? Если это так, я бы предпочел не делать вызовы командной строки, если есть OO способ сделать вызовы программно, как в примере файла BuiltTest.PL.
Показать ещё 6 комментариев
14

В ответ на Курта я предлагаю эту альтернативу его встроенной версии .PL script.

use strict;
use warnings;
use Module::Build;

my $build = Module::Build->resume (
  properties => {
    config_dir => '_build',
  },
);

$build->dispatch('build');
$build->dispatch('test');

Повторно использует сборку базы данных Build.PL(и, следовательно, предполагает, что она уже запущена).

  • 0
    Отлично! Спасибо, Леон. Я знал, что с моим примером что-то не так, но я все еще новичок в этой сборке perl! :-)
12

Фантастически полезный module-starter создает простой в использовании проект скелета, который обрабатывает установку модуля, создание документации и хороший макет для файлы модулей для работы, и - я думаю - поддержка покрытия кода. Это ИМО - отличное начало для любого процесса, связанного с модулем Perl.

Также: использование CPAN-связанных инструментов, таких как Module::Build - даже для модулей, которые, вероятно, никогда не будут опубликованы публично - - очень хорошая идея.

12

Я описываю это в промежуточном Perl, а также Освоение Perl. Курт, однако, дал хорошее резюме.

Я все это объединяю в release script, используя Module:: Release. Я набираю одну команду, и все это происходит.

7

(раскрытие: я автор)

После того, как вы все отсортировали, как описано выше, вы можете сделать следующий шаг и использовать Devel:: CoverX:: Covered, например,

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

Обратитесь к synopsis для конкретных примеров командной строки.

В Devel:: PerlySense там Emacs поддерживает отображение информации о покрытии в буфере исходного кода (скриншот), а также для перехода к/из покрытия тестовых файлов.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню