2010-05-18 4 views
3

Мне нужно построить модульные тесты в среде с очень старой версией Test::More (perl5.8 с $Test::More::VERSION being '0.80'), которая предшествовала добавлению done_testing().Каков самый идиоматический способ эмуляции теста Perl :: More :: done_testing?

Обновление до более нового теста :: Больше не может быть и речи по практическим соображениям. И я стараюсь избегать использования no_tests - это, как правило, плохая идея не ловить, когда ваш юнит-тест выходит преждевременно - скажем, из-за какой-то логики, которая не выполняется, когда вы этого ожидали.

Что является наиболее идиоматическим способом запуска настраиваемого количества тестов, не предполагая no_tests или done_testing() используются?


Детали:

Мои юнит-тесты обычно принимают форму:

 
use Test::More; 
my @test_set = (
    [ "Test #1", $param1, $param2, ... ] 
    ,[ "Test #1", $param1, $param2, ... ] 
    # ,... 
); 

foreach my $test (@test_set) { 
    run_test($test); 
} 

sub run_test { 
    # $expected_tests += count_tests($test); 
    ok(test1($test)) || diag("Test1 failed"); 
    # ... 
} 

Стандартный подход use Test::More tests => 23; или BEGIN {plan tests => 23} не работает так как, очевидно, выполняется перед тем @tests известно ,


Мой текущий подход предполагает создание @tests глобального и определения его в BEGIN {} блоке следующим образом:

 
use Test::More; 
BEGIN { 
    our @test_set =(); # Same set of tests as above 
    my $expected_tests = 0; 
    foreach my $test (@tests) { 
     my $expected_tests += count_tests($test); 
    } 
    plan tests => $expected_tests; 
} 
our @test_set; # Must do!!! Since first "our" was in BEGIN's scope :(
foreach my $test (@test_set) { run_test($test); } # Same 
sub run_test {} # Same 

Я чувствую, что это может быть сделано более идиоматически, но не уверен, как улучшить. Главным среди запахов является дубликат our @test_test деклараций - в BEGIN{} и после него.


Другой подход заключается в эмулировать done_testing() по телефону Test::More->builder->plan(tests=>$total_tests_calculated). Я не уверен, что это лучше идиоматично.

+2

Каковы практические причины не модернизации Test :: More? – Schwern

+1

Под «no_tests» я полагаю, вы имеете в виду «no_plan»? Он отлично работает, если ваш тест умирает преждевременно. Единственное условие, при котором проблема «no_plan» становится проблемой, заключается в том, что ваш тест выходит рано и обычно. Попробуй. – Schwern

+1

@Schwern - это основной модуль. Получение программного обеспечения для его утверждения потребует больше времени и усилий (рецензии, презентации, убедительное управление, тестирование всей компании), чем я могу обосновать руководство, когда единственный компромисс - это более простые тесты устройства – DVK

ответ

1

Как насчет использования замыкания для возврата тестовых наборов, что позволяет избежать неловкости переменной пакета?Вот иллюстрация:

use strict; 
use warnings; 
use Test::More; 

BEGIN { 
    my @ts = (
     [ 'Test 1', 1, 1 ], 
     [ 'Test 2', 3, 3 ], 
    ); 

    plan tests => scalar @ts; 

    sub test_sets { return @ts } 
} 

for my $ts (test_sets()){ 
    run_test($ts); 
} 

sub run_test { 
    my ($msg, $val, $exp) = @{shift()}; 
    is $val, $exp, $msg; 
} 
+0

@FM - Yay! Затворы! +1 – DVK

3

Не взламывайте старые версии, просто отправьте копию Test :: More. У него нет зависимостей. Просто установите его в t/lib вашего дистрибутива (вы можете его построить, а затем скопировать blib/lib), а затем use lib "t/lib" в свои тесты.

+0

@Schwern - разработка программного обеспечения на самом деле проверяет тестовый код. Если бы я это сделал, сценарий ** наилучшего случая ** был бы большим жеванием управляющим директором, руководившим этой командой. К сожалению, я играю по корпоративным правилам игры. Если вы хотите знать, что происходит, никто этого не делает, спросите г-на Оригинала Just Another Perl Hacker (http://www.lightlink.com/spacenka/fors/) :( – DVK

+1

@ DVK Замазанный для чего? Test :: More является специфичным для ваших тестов. Он не влияет на чей-либо код. – Schwern

+0

@Schwern - использование локальных копий модулей CPAN - это ... как я должен его надеть ... нахмурился. – DVK

1

Вот довольно идиоматический подход:

use warnings; 
use strict; 
use Test::More; 
use List::Util 'sum'; 

sub count_tests {1} 

BEGIN { 
    plan tests => sum map { 
     count_tests($_) 
    } @test::set = (
     [ "Test #1", '$param1, $param2, ...' ], 
     [ "Test #1", '$param1, $param2, ...' ], 
    ) 
} 

run_test($_) for @test::set; 

Использование полного имени позволяет избежать необходимости our, вы можете также использовать @::test_set, если вы беспокоитесь о положить что-то в test:: пакете. И используя map и sum от List::Util сокращает код в BEGIN блоке немного. Функциональная форма также инвертирует поток данных, что позволяет объявлять все тесты в конце, удерживая вызов plan наверху, чтобы напомнить, почему в первую очередь использовался блок BEGIN.

+0

Эрик. Мне нравится идея положить что-то в тестовый пакет. +1 – DVK

1

Если вам нужно только рассчитать план, основанный на таблице тестов, это тривиально.

use Test::More; 

my $Asserts_Per_Set = 10; 
my %Tests = (
    "Test #1" => { foo => "bar", this => "that" }, 
    "Test #2" => { foo => "yar", this => 42  }, 
    ... 
); 

plan tests => keys %Tests * $Asserts_Per_Set; 

for my $name (keys %Tests) { 
    run_tests($name, $Tests{$name}); 
} 

Если по какой-то причине run_tests необходимо запустить переменное число тестов, основанных на данных, использовать skip, а не как if поэтому он всегда работает последовательный ряд тестов.

SKIP: { 
    skip "Can't run foo test on frobnitz", 2 if $test->{foo} and $test->{frobnitz}; 

    is foo(), $test->{foo}; 
    is bar(), $test->{foo} + 9; 
} 

Для чего-либо более сложного, добавить к плану, как вы идете путем использования BEGIN блоков.

use Test::More; 
my $Count; 

BEGIN { $Count += X } 

...run X tests... 

BEGIN { $Count += Y } 

...run Y tests... 

BEGIN { plan tests => $Count } 

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

Кстати, новые версии Test :: More имеют subtest, чтобы лучше справляться с проблемой разбивки теста на несколько планов.

Смежные вопросы