2009-10-08 8 views

Odpowiedz

32

UPDATE: IMHO, prawidłowa odpowiedź na to pytanie powinna być użycie 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'); 

wyjściowa:

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

Wyjeżdżam oryginalnego odpowiedź dla odniesienia jak, Wierzę, że nadal ilustruje przydatną technikę:.

można zlokalizować STDOUT i ponownie do skalara przed wywołaniem funkcji przywracania potem:

#!/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'"); 

wyjściowa:

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

Dla wersji perl starszych niż 5,8, to prawdopodobnie trzeba użyć IO::Scalar, ale nie wiem zbyt wiele o tym, jak rzeczy działały przed 5.8.

+4

Właśnie wtedy, gdy myślę, że tracę zbyt dużo czasu na SO, uczę się czegoś fajnego! Dzięki. – FMc

+0

Cóż, technicznie nie, ale na pewno jest fajnie, kiedy to robią. : p (+1, to niesamowity moduł) –

+0

Nie pochwaliłem tego, ale myślę, że odpowiedź orginalna robi za dużo pracy, aby wykonać zadanie. To zbyt skomplikowane. Jestem nieco stronniczy w Test :: Output, ale używam go w ostateczności. –

7

Spróbuję pozwolić, aby moduł sobie z tym poradził. Spójrz na Capture::Tiny.

+0

+1 Nie wiedziałem o Capture :: Tiny. –

5

Jeśli jest to kod, który sam piszesz, zmień go tak, aby instrukcje drukowania nie używały domyślnego uchwytu pliku. Zamiast dać sobie drogę do ustawiania uchwytu pliku wyjściowego do wszystkiego co lubię:

 
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 

Podczas testowania, można zadzwonić _set_output_fh, aby nadać mu swój uchwytu pliku testowego (być może nawet IO::Null handle). Gdy inna osoba chce użyć twojego kodu, ale przechwytuje dane wyjściowe, nie musi się pochylać do tyłu, aby to zrobić, ponieważ może dostarczyć własną uchwyt pliku.

Po znalezieniu części kodu, która jest trudna do przetestowania lub musisz przeskoczyć przez obręcze do pracy, prawdopodobnie masz zły projekt. Nadal jestem zdumiony tym, że testowanie kodu sprawia, że ​​te rzeczy są oczywiste, ponieważ często nie myślałem o nich. Jeśli jest to trudne do sprawdzenia, ułatw to testowanie. Generalnie wygrywasz, jeśli to zrobisz.

+0

Amen. Pisanie testów jednostkowych (lub planowanie dla nich, jeśli robisz TDD, czy wiesz, czy nie) bardzo często powoduje znaczące ulepszenia projektu. – DVK

Powiązane problemy