2009-10-08 9 views

risposta

32

UPDATE: IMHO, la risposta corretta a questa domanda dovrebbe essere quello di utilizzare 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'); 

uscita:

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

Lascio la risposta originale per riferimento, Credo, illustra ancora una tecnica utile.

È possibile localizzare STDOUT e riaprire ad uno scalare prima di chiamare la funzione, il ripristino in seguito:

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

uscita:

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

Per le versioni di perl di età superiore a 5,8, probabilmente è necessario utilizzare IO::Scalar, ma non so molto su come funzionavano le cose prima del 5.8.

+4

Proprio quando penso di perdere troppo tempo in SO, imparo qualcosa di interessante! Grazie. – FMc

+0

Beh, tecnicamente no, ma sicuramente è bello quando lo fanno. : p (+1, questo è un modulo fantastico) –

+0

Non l'ho svalutato, ma penso che la risposta originale faccia troppo lavoro per portare a termine il lavoro. È troppo complicato Sono un po 'prevenuto verso Test :: Output, però, ma lo uso come ultima risorsa. –

7

Guarderei lasciare che un modulo gestisca questo per voi. Guarda Capture::Tiny.

+0

+1 Non sapevo di Capture :: Tiny. –

5

Se questo è il codice che si sta scrivendo, modificarlo in modo che le istruzioni di stampa non utilizzino un filehandle predefinito. Invece, per te è un modo per impostare il filehandle di output a qualcosa che ti piace:

 
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 

Quando si prova, è possibile chiamare _set_output_fh per dare il filehandle test (forse anche un IO::Null maniglia). Quando un'altra persona vuole usare il tuo codice ma cattura l'output, non deve piegarsi all'indietro per farlo perché può fornire il proprio filehandle.

Quando trovi una parte del tuo codice che è difficile da testare o che devi saltare attraverso i cerchi con cui lavorare, probabilmente hai un cattivo design. Sono ancora stupito di come il codice di test rende queste cose evidenti, perché spesso non ci penso. Se è difficile da testare, rendilo facile da testare. Generalmente vinci se lo fai.

+0

Amen. I test di unità di scrittura (o la pianificazione per loro se si fa TDD, che tu lo sappia o meno) molto spesso si traduce in miglioramenti del design marcati. – DVK

Problemi correlati