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

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

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

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

5 ответов

Решение

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

Начните с каталога для вашего проекта 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". Этот файл - ваш скрипт модульного тестирования, который попытается полностью протестировать ваш модуль 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_addy@goes.here>',
    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. Перейдите в этот каталог и дважды щелкните файл "cover.html", чтобы открыть отчет о покрытии кода в своем любимом веб-браузере. Он дает вам хороший гипертекстовый отчет с цветовой кодировкой, в котором вы можете щелкнуть по имени вашего файла и просмотреть подробную статистику покрытия операторов, ветвей, условий, подпрограмм для вашего модуля Perl прямо в отчете рядом с фактическим исходным кодом. В этом отчете вы можете видеть, что мы вообще не покрывали подпрограмму "bye()", а также есть строка кода, которая недоступна, но не была покрыта, как мы ожидали.


(источник: leucht.com)

Еще одна вещь, которую вы можете сделать, чтобы помочь автоматизировать этот процесс в вашей среде 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") одним щелчком мыши, и он автоматически запускает мой код модульного тестирования из IDE, а не я делаю это вручную из командной строки. Замените "dispatch('test')" на "dispatch('testcover')" для автоматического выполнения покрытия кода. Введите "Справка по сборке", чтобы получить полный список целей сборки, доступных в Module::Build.

В ответ Курту я бы предложил эту альтернативу его скрипту BuiltTest.PL.

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

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

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

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

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

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

Я расскажу об этом в Промежуточном Perl, а также в Mastering Perl. Курт, однако, дал хорошее резюме.

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

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

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

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

Смотрите краткий обзор конкретных примеров командной строки.

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

Другие вопросы по тегам