Последнее в категории Тесты

В очередной раз подумалось, что код из блока SYNOPSIS POD-документации модулей на спане нужно автоматически включать в набор тестов.

Вот модуль Time::Business, судя по описанию, полезный: умеет переводить рабочие часы в «общечеловеческие». CPAN сообщает о десятках успешных тестов на разных платформах. Но в действительности к модулю прилагается только тест use_ok (это не самое страшное), а код из краткого описания не работает:

use v5.12;
use Time::Business;

my $bt = new Time::Business ({
    WORKDAYS => [1..5],
    STARTTIME => 1000,
    ENDTIME => 1900,
});
my $seconds = $bt->calctime(time, time + 1 * 86400);

perl test.pl
Can't locate object method "calctime" via package "Time::Business" at test.pl line 9.

Понятно, что дальнейшее чтение документации помогает добиться работоспособности, но внутренний голос сразу начинает говорить о том, что как-то и все остальное некрасиво: и странный формат записи времени (а что, если записать 0800 — не в восьмеричном ли формате это получится?), и капслок в именах ключей, и отсутствие предопределенных значений — собственно, все то, что замечаешь при первом взгляде, но что лишь усиливает негатив после того, как первый тест не заработал.

Про XXX

| Комментариев: 2

На спане есть модуль Инги дёт Нета (Брайана Ингерсона) под названием XXX, предназначенный для — ха! — для отладки.

Модуль экспортирует несколько функций WWW, XXX, YYY и ZZZ, которые печатают дамп того, что находится справа. То есть достаточно вписать в нужное место XXX, и выполнение программы прекратится отладочным сообщением:

use v5.12;
use XXX;

XXX my @digits = 'a'..'f';

--- a
--- b
--- c
--- d
--- e
--- f
...
  at 1.pl line 4

По умолчанию дамп делается в формате YAML, но это возможно переопределить, например:

use v5.12;
use XXX -with => 'Data::Dumper';

XXX my $person = {sex => 'male', age => 30};

$VAR1 = {
  'age' => 30,
  'sex' => 'male'
};

  at 2.pl line 4

Вызов XXX приводит к завершению программы (die), а WWW печатает предупреждение (warn).

Несмотря на то, что все равно приходится явно подключать модуль (use XXX), подход очень интересный: написать в начале (или любой другой части — функция возвращает все свои аргументы) строки три буквы (хотя еще удобнее было бы, если бы названия функция были в нижнем регистре) намного проще и быстрее, чем, например, say Data::Dumper($var).

Data::Maker

| Нет комментариев

Есть такой модуль — Data::Maker, с помощью которого возможно готовить наборы тестовых (или, если угодно, фейковых) данных в разных форматах.

Простейший пример по мотивам примера из документации все объясняет:

use v5.10;
use strict;
use Data::Maker;

my $maker = Data::Maker->new(
    record_count => 5,
    fields => [
        {
            name => 'phone',
            format => '+7 \d\d\d \d\d\d-\d\d-\d\d',
        },

    ]
);


while (my $item = $maker->next_record) {
    say $item->phone->value;
}

Эта программа печатает пять телефонных номеров в формате, указанном при создании объекта Data::Maker:

+7 536 209-69-11
+7 119 599-52-63
+7 778 591-94-25
+7 723 863-71-04
+7 894 976-58-35

Теперь более сложный пример. В каждом случайном объекте помимо телефона будут формироваться имя, фамилия, а заодно и дата рождения.

Если номер телефона генерировался по заданной маске, напоминающей регулярное выражение, то логика для остальных полей реализована внутри соответствующих классов, например, Data::Maker::Field::DateTime. Ему, кстати, возможно передать параметры (какие именно, видно в исходнике).

use v5.10;
use strict;
use Data::Maker;
use Data::Maker::Field::Person::FirstName;
use Data::Maker::Field::Person::LastName;
use Data::Maker::Field::DateTime;

my $maker = Data::Maker->new(
    record_count => 10,
    fields => [
        {
            name => 'phone',
            format => '+7 \d\d\d \d\d\d-\d\d-\d\d',
        },
        {
            name => 'firstname',
            class => 'Data::Maker::Field::Person::FirstName',
        },
        {
            name => 'lastname',
            class => 'Data::Maker::Field::Person::LastName',
        },
        {
            name => 'birthday',
            class => 'Data::Maker::Field::DateTime',
            args => {
                start => 1980,
                end => 1990,
            },
        },
    ]
);


while (my $item = $maker->next_record) {
    say $item->firstname->value, ' ',
        $item->lastname->value, "\t",
        $item->phone->value, "\t",
        $item->birthday->value;
}

Результат работы:

Sherrie Webster +7 001 585-82-85        1985-12-07T07:56:59
Opal Merrill    +7 235 817-78-63        1985-07-28T05:10:55
Erik Miles      +7 252 016-71-82        1988-05-30T08:47:48
Darlene Peters  +7 038 976-13-95        1981-12-10T02:53:20
Michael Salinas +7 039 850-43-23        1982-09-22T09:44:26
Sallie Roth     +7 404 102-02-88        1989-04-06T23:47:54
Renee Lowe      +7 975 958-07-91        1981-04-10T23:00:27
Deanna Rocha    +7 442 730-46-48        1987-05-26T15:11:47
Rena Benson     +7 535 737-78-68        1987-12-01T17:11:34
Ella Obrien     +7 064 783-65-38        1986-03-20T11:36:36

Автор честно признается, что скорость работы генератора довольно низкая. Тем не менее, это интересный модуль, который может быть полезен для тестов.

P. S. Moose настолько проникает в разработчика, что даже краткое описание модуля Data::Maker::Field содержит технические детали: a Moose role that is consumed by all Data::Maker field classes; the ones included with Data::Maker and the ones that you write yourself to extend Data::Maker's capabilities.    

Соль минор

| Нет комментариев

Я хотел написать про одно, а напишу про другое.

Сегодня мне стало интересно, что на спане умеет рисовать ноты. Оказалось, не так уж и много. Есть пара интересных модулей, которые умеют делать картинки с клавишами, которые нужно нажать, получая на входе название аккорда.

Например, модуль GD::Chord::Piano рисует такие простые картинки:

chord.png

Интерфейс крайне прост и приятен:

use GD::Chord::Piano;
my $im = GD::Chord::Piano->new;
print $im->chord('Gm')->png;

Все, что требуется, — передать название аккорда методу chord. Этот пример скопирован из документации к модулю.

А вот другой модуль — Music::Image::Chord, который, судя по названию и описанию, должен делать нечто похожее.

Но если скопировать пример из документации, то ничего не работает:

Use of uninitialized value in division (/) at /usr/local/lib/perl5/site_perl/5.10.0/Music/Image/Chord.pm line 152.
Can't use an undefined value as a HASH reference at /usr/local/lib/perl5/site_perl/5.10.0/Music/Image/Chord.pm line 153.

Нет, можно конечно продолжить разбираться, но не хочется.

К сожалению, такое весьма часто такое случается с примерами в книгах, причем не из-за того, что у автора и читателя оказались компиляторы разных версий. А ведь это так просто — скопипейстить код из набранной рукописи и проверить ее.

У разработчиков периодически возникают ситуации, когда они уверены в написанном коде и не проверяют его. Ну разве можно ошибиться, исправив один-два символа в регулярном выражении на боевом сервере? А вот можно :-) Сила опытного разработчика не в том, что он может писать код с закрытыми глазами, а в том, что он не стремается проверять себя.

В качестве офтопика можно вспомнить историю, расказанную создателем Бейсика Томасом Курцом о том, что какой-то аспирант написал компилятор PL/1 без отладки, впервые запустив его только после того, как код был полностью написан:

...he worked at Darthmouth in the computer center. He wrote a PL/1 compiler, and it's a big thing, and he checked it, and looked at it, and so on, but he never tested it, he never ran it until it was all done. You know, 20,000 or 30,000 lines of code, and the only test he did was to read it. Then he ran it and it worked the first time!

В той же книге рассказано и о том, что означат отладка для создателя C++ Бьярна Страуструпа:

— How do you debug? Do you have any suggestion for C++ developers?
— By introspection. I study the program for so long and poke at it more or less systematically for so long that I have sufficient understanding to provide an educated guess where the bug is.

Они любят читать программы, это здорово. Но в нашем распоряжении есть мириады модулей для автоматического тестирования кода, которыми пользуются, к сожалению, не так часто, как этого можно желать.

Тесты Perl 1

| Нет комментариев

Набор тестов, входящий в состав дистрибутива Perl 1, выполняется Perl 5.10 на 91%.

В книге Masterminds of Programming, в которой собраны интервью с создателями семнадцати языков программирования, я прочитал, как Ларри Уолл заметил, что многие тесты, которые были написаны для первой версии перла, правильно работают и под Perl 5.

Что ж, пробуем.

Дистрибутив Perl 1 доступен на сайте dev.perl.org. В нем есть папка t, в которой находятся около 50 файлов с тестами:

base.cond, base.if, base.lex, base.pat, base.term, cmd.elsif, cmd.for, cmd.mod, cmd.subval, cmd.while, comp.cmdopt, comp.cpp, comp.decl, comp.multiline, comp.script, comp.term, io.argv, io.fs, io.inplace, io.print, io.tell, op.append, op.auto, op.chop, op.cond, op.crypt, op.do, op.each, op.exec, op.exp, op.flip, op.fork, op.goto, op.int, op.join, op.list, op.magic, op.oct, op.ord, op.pat, op.push, op.repeat, op.sleep, op.split, op.sprintf, op.stat, op.subst, op.time, op.unshift

Имена довольно необычны для современных тестов. В добавок в комплекте есть файл TEST, который выполняет роль современной утилиты prove. Сам этот файл работать не хочет, но prove вполне работает:

$ prove *.*

Сводка с результатом работы выглядит так:

Failed 14/49 test scripts. 26/305 subtests failed.
Files=49, Tests=305,  7 wallclock secs ( 1.39 cusr +  0.47 csys =  1.86 CPU)
Failed 14/49 test programs. 26/305 subtests failed.

Из 305 тестов с ошибкой завершились только 26. И это после 20 лет разрабоки языка, невероятно!

Страницы

  • img

Об архиве

Эта страница содержит последние записи категории Тесты.

Предыдущая категория — Стиль кода.

Следующая категория — Язык.

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