Как я могу протестировать функции Perl, которые выводят на экран? - PullRequest
34 голосов
/ 08 октября 2009

Я пытаюсь использовать Test :: More для модульного тестирования функций Perl, печатающих на экран.

Я понимаю, что этот вывод может мешать таким инструментам, как Доказать .

Как мне захватить этот вывод, чтобы я мог напечатать его с diag(), а также запустить тесты на самом выходе?

Ответы [ 3 ]

32 голосов
/ 08 октября 2009

ОБНОВЛЕНИЕ: ИМХО, правильный ответ на этот вопрос следует использовать Test :: Output :

#!/usr/bin/perl

use strict; use warnings;

use Test::More tests => 1;
use Test::Output;

sub myfunc { print "This is a test\n" }

stdout_is(\&myfunc, "This is a test\n", 'myfunc() returns test output');

Выход:

C:\Temp> tm
1..1
ok 1 - myfunc() returns test output

Я оставляю исходный ответ для справки, так как, я думаю, он все еще иллюстрирует полезную технику .

Вы можете локализовать STDOUT и открыть скаляр перед вызовом функции, затем восстановить:

#!/usr/bin/perl

use strict; use warnings;

use Test::More tests => 1;

sub myfunc { print "This is a test\n" }

sub invoke {
    my $sub = shift;
    my $stdout;
    {
        local *STDOUT;
        open STDOUT, '>', \$stdout
            or die "Cannot open STDOUT to a scalar: $!";
        $sub->(@_);
        close STDOUT
            or die "Cannot close redirected STDOUT: $!";
    }
    return $stdout;
}

chomp(my $ret =  invoke(\&myfunc));

ok($ret eq "This is a test", "myfunc() prints test string" );
diag("myfunc() printed '$ret'");

Выход:

C:\Temp> tm
1..1
ok 1 - myfunc() prints test string
# myfunc() printed 'This is a test'

Для версий perl старше 5.8 вам, вероятно, нужно использовать IO :: Scalar , но я не очень разбираюсь в том, как все работало до 5.8.

7 голосов
/ 08 октября 2009

Я бы посмотрел на то, чтобы модуль смог обработать это для вас. Посмотрите на Capture :: Tiny .

6 голосов
/ 09 октября 2009

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

sub my_print {
     my $self = shift;
     my $fh = $self->_get_output_fh;
     print { $fh } @_;
     }

sub _get_output_fh { $_[0]->{_output}  || \*STDOUT }
sub _set_output_fh { $_[0]->{_output} = $_[1] } # add validation yourself

Когда вы тестируете, вы можете позвонить _set_output_fh, чтобы передать ему свой тестовый файл (возможно, даже IO :: Null ). Когда другой человек хочет использовать ваш код, но захватывает вывод, ему не нужно наклоняться назад, чтобы сделать это, потому что он может предоставить свой собственный файловый дескриптор.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...