worldmind (worldmind) wrote in ru_perl,
worldmind
worldmind
ru_perl

Category:

Perl: Нефункциональное модульное тестирование - "главное чтобы блестел"

Про модульные тесты писалось наверно не мало, но уверен что не многие их реально пишут. Начать писать тесты бывает сложно чисто психологически, поэтому я предлагаю начать с малого - просто запустить готовые тесты. В этой заметке я бы хотел рассказать не о тестировании функционала самих модулей (это в следующие раз), а об инфраструктуре тестирования и о тестах которые говорят: "незнаю работает ли этот код, но выглядит неплохо".
Такие тесты нужно подготовить один раз и потом использовать во всех проектах т.е они не требуют усилий по разработке, но при это дают вам неплохое представление о состоянии вашего кода.
Итак, перед вами встала задача разработать программу с неким функционалом, большая часть кода у вас скорее всего будет вынесена в модули. Для создания заготовки модуля используем созданную для CPAN автором утилиту module-starter (ставиться с модулем Module::Starter)
выполняем:
module-starter --mi --module=Module::Name --author="worldmind" --email="world.mind@yahoo.com"
в результате будет создана папка Module-Name со следующей структурой

|-- Changes
|-- MANIFEST
|-- Makefile.PL
|-- README
|-- ignore.txt
|-- lib
| `-- Module
| `-- Name.pm
`-- t
|-- 00-load.t
|-- boilerplate.t
|-- manifest.t
|-- pod-coverage.t
`-- pod.t

папка lib это наш модуль, в папке t заготовлены простенькие тесты (с boilerplate.t я не разбирался, незнаю что он творит), для их выполнения нужно
1. выполнить perl Makefile.PL - будет создан Makefile (можно потом и make выполнить, но нам сейчас это неважно)
2. выполнить make test - будут запущены тесты
Результат тестирования выводится в формате TAP (Test Anything Protocol), после выполнения это команды вы увидите примерно следущее

t/00-load.t ....... 1/1 # Testing Module::Name 0.01, Perl 5.010001, /usr/bin/perl
t/00-load.t ....... ok
t/boilerplate.t ... ok
t/manifest.t ...... skipped: Author tests not required for installation
t/pod-coverage.t .. ok
t/pod.t ........... ok
All tests successful.
Files=5, Tests=6, 1 wallclock secs ( 0.10 usr 0.04 sys + 0.45 cusr 0.12 csys = 0.71 CPU)
Result: PASS

Все тесты успешно пройдены, один пропущен т.к. предназначен только для CPAN авторов

Теперь мы немного изменим и дополним набор тестов:


0. В 00-load.t и boilerplate.t удалим первую строку #!perl -T

1. Создадим файл 01-strict.t следующего содержания

use strict;
use warnings;

use Test::Strict;

all_perl_files_ok('lib'); # Syntax ok and use strict;

это проверка синтаксиса и наличия прагмы use strict (можно ещё проверку на use warnings добавить, но я пока поленился, как-нибудь добавлю)

2. Создадим файл 02-fixme.t

use strict;
use warnings;

use Test::Fixme;
run_tests(
where => ['lib'], # where to find files to check
match => qr/FIXME/, # what to check for
);

Он будет проверять что в коде не осталось пометок FIXME. Т.е. в процессе разработки вы можете оставлять для себя пометки и тесты не дадут вам забыть о них.

3. 03-critic.t

use strict;
use warnings;

use Test::Perl::Critic;

all_critic_ok('lib');

Это тест скажет хорош ли ваш с код с точки зрения PBP (Perl Best Practice), проверка осуществляется с помощью модуля Perl::Critic.


Итак, мы добавили несколько тестов оценивающих наш код, по хорошему нужно добавить ещё тест на цикломатическую сложность.
(если сильно высокий уровень сложности, то значит мы накодили что-то сильно сложное для сопровождения и надобы декомпозировать), делается это с помощью модуля Test::Perl::Metrics::Simple, но он у меня сходу не поставился и я пока отложил его освоение написав автору.

4. Тесты для тестирования документации у нас сгенерировались автоматически, переименуем их (для того чтобы они выполнялись по порядку, не критично, но мне кажется так аккуратнее), получим
06-pod.t (тут я убрал первую строку #!perl -T)
07-pod-coverage.t
первый проверяет валидность POD, второй проверяет что все методы имеют POD документацию

5. Теперь проверим сами тесты, точнее процент покрытия кода тестами - покрытие кода
08-code-coverage.t

use strict;
use warnings;

use Test::Strict;

all_cover_ok( 80, 't/' );

Какую цифру считать достаточным покрытием решать вам, она сильно зависит от сложности проекта, в простых модулях можно достичь высокой степени покрытия (> 90), но на практике часто бывает что такой проценрт достичь излише сложно, возможно где-то хватить и 50% покрытия

6. Осталось проверить насколько полно укомплектован наш дистрибутив
09-kwalitee.t

use strict;
use warnings;

use Test::More;

eval {
require Test::Kwalitee;
Test::Kwalitee->import()
};

plan( skip_all => 'Test::Kwalitee not installed; skipping' ) if $@;

manifest.t можно удалить т.к. аналогичная проверка есть в 09-kwalitee.t

Замечание: в некоторых тестах явно указана папка lib, возможно вам нужно будет вписать в них ещё папку bin

Теперь выполняем
perl Makefile.PL
make
make test


и получаем
All tests successful.
Files=9, Tests=33, 22 wallclock secs ( 0.16 usr 0.06 sys + 19.54 cusr 2.20 csys = 21.97 CPU)
Result: PASS


Замечание: возможно будут варнинги от Devel::Cover (надо будет глянуть что там не так), но главное тесты успешны (если у вас установлены все необходимые модули)

Ссылки
http://perl-qa.hexten.net/wiki/index.php/Main_Page
http://qa.perl.org/
http://qa.perl.org/test-modules.html

Книги
Perl Testing: A Developer's Notebook by Ian Langworth, Chromatic
An Introduction to Test Driven Development Using Perl by Grant McLean.

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

UPD. - полученный исходники в архиве - http://narod.ru/disk/2454679001/Module-Name-tests.tar.gz.html
Tags: perl, unit testing, технологии
Subscribe

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 13 comments
Спасибо, Алексей.

Полезный пост.
Я и сам хотел написать про Module::Starter и Module::Build,
но Вы меня опередили, иэ это хорошо, я рад.

Всё-таки настолько тяжело в перле что-то правильно начать делать,
поскольку язык гипергибкий и много переложено с синтаксиса на best practices.
А эти самые best practices сегодня одни, а завтра другие.
И понять, что правильно, как диплоить код, как удалить модуль "не руками"
и всё в таком духе - очень тяжело. Где-то это по кулуарам,
по углам нашушукано, науськано, и никто не берётся выйти и сказать:
"делать правильно так", потому что пацаны-то могут и засмеять
"да у нас уж два сезона так не делают" и т.д.

Народ вон резвится в гонке Planet Iron Man,
восклицает - прапагандируйте, мол, пёрл, мы живы. мы живы, -
а я считаю, что серия подробнейших постов "неснобистский пёрл"
вместо этой гонки была бы очень полезна для сообщества.
Ваш пост как раз из таких.
Для перловиков из пролетарской, рабоче-крестьянской среды,
а не для интеллектуалов в 5-ом колене.
Спасибо за оценку, а про Module::Starter я подглядел у mons
http://codesign.livejournal.com/46779.html
Это было бы прекрасно - тексты для не-совсем-новичков.

Есть тексты по самым азам "а это, дети, называется переменная", и есть тексты для знатоков, говорящих со знатоками же. А до не-совсем-новичков-но-совсем-не-профи как-то обычно дело не доходит. :)

Кстати, можно быть интеллектуалом в пятом колене, но абсолютно не ориентироваться в перловых "наилучших обыкновениях". Я проверяла. :)
хорошая статья

Я бы ещё упомянул для тех у кого уже написаный проект и без Makefile (а таких, ух как не мало) полезную утилиту: prove
Как вариант создать Makefile следующего содержания
test:
perl -MTest::Harness -e 'runtests(@ARGV)' t/*.t

во второй строке табуляция
test:
prove

так меньше писанины ;)
Удачи Вам в Новом Году!
И много-много хороших статей и обзоров.
git clone git@github.com:worldmind/perl-test-code-quality-template.git
Заметка не вызвала большого отклика т.к. начать писать тесты бывает не просто сложно психологически, а очень сложно )

Если серьёзно, то спасибо за пост.
По сути пока мало что могу сказать, т.к. только подбираюсь к тестированию.

У меня как раз задача - достался код, который никаких тестов не содержит. Как-то всё работает более-менее, как-то вносятся мелкие исправления, как-то тестируется на uat. И действительно, подступиться не просто. Мысль, которую сложно вытеснить из подсознания - ну ладно, потом доберусь до тестов, сейчас и так работает вроде бы.

Плюс написание тестов, возможно, потребует реорганизации кода.
Продолжение тут http://habrahabr.ru/blogs/perl/111655/
Моё мнение состоит в том что самые примитивные тесты (вызов каждого метода один раз с заведомо корректными значениями) намного лучше чем вообще без тестов, а старый код это конечно проблема
спасибо за полезный и интересный пост!
А можете сделать его кросспост на rootfront.com ? Либо я могу сам его опубликовать с ссылкой на Вас и Ваш блог.
Спасибо!
Публикуйте
еще неплохо бы результаты тестирования посмотреть в хтмл, например так
prove -l -Q --formatter=TAP::Formatter::HTML > out.html