Сборка Perl, модульное тестирование, покрытие кода: полный рабочий пример - PullRequest
83 голосов
/ 10 февраля 2009

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

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

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

Ответы [ 5 ]

102 голосов
/ 10 февраля 2009

Мне потребовалось некоторое время, а также я взял небольшие фрагменты из разных источников и соединил их вместе, но я думаю, что у меня есть небольшой рабочий пример, который достаточно демонстрирует новичку в 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». Этот файл - ваш скрипт модульного тестирования, который попытается полностью протестировать ваш модуль 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 ()", а также есть строка кода, которая недоступна, и не была покрыта, как мы ожидали.

snapshot of code coverage report
(источник: 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.

14 голосов
/ 10 февраля 2009

В ответ Курту я бы предложил эту альтернативу его скрипту 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 (и, следовательно, предполагает, что она уже запущена).

12 голосов
/ 11 февраля 2009

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

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

12 голосов
/ 11 февраля 2009

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

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

7 голосов
/ 16 августа 2009

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

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

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

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

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

...