2009-10-08 5 views

Respuesta

32

ACTUALIZACIÓN: en mi humilde opinión, la respuesta correcta a esta pregunta debe ser el uso de 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'); 

Salida:

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

dejo la respuesta original para referencia, Creo que todavía ilustra una técnica útil.

Puede localizar STDOUT y volver a abrir a un escalar antes de llamar a la función, restaura después:

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

Salida:

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

Para las versiones de perl mayores de 5,8, es probable que necesite usar IO::Scalar, pero no sé mucho sobre cómo funcionaban las cosas antes de 5.8.

+4

Justo cuando creo que estoy perdiendo demasiado tiempo en SO, ¡aprendo algo genial! Gracias. – FMc

+0

Bueno, técnicamente no, pero seguro que es bueno cuando lo hacen. : p (+1, es un módulo impresionante) –

+0

No lo voté negativamente, pero creo que la respuesta original hace demasiado trabajo para hacer el trabajo. Es demasiado complicado. Sin embargo, estoy un poco predispuesto hacia Test :: Output, pero lo uso como último recurso. –

7

Me gustaría dejar que un módulo lo maneje por usted. Mira Capture::Tiny.

+0

+1 No sabía acerca de Capture :: Tiny. –

5

Si este es el código que está escribiendo usted mismo, cámbielo para que las instrucciones de impresión no usen una manejador de archivos predeterminado. En su lugar, dése una manera de establecer el gestor de archivo de salida a lo que quiera:

 
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 

Cuando se prueba, puede llamar _set_output_fh para darle su gestor de archivo de prueba (tal vez incluso un mango IO::Null). Cuando otra persona quiere usar su código pero capturar el resultado, no tiene que hacer todo lo posible para hacerlo porque puede proporcionar su propio identificador de archivo.

Cuando encuentra que una parte de su código es difícil de probar o que tiene que pasar por aros para trabajar, es probable que tenga un diseño incorrecto. Todavía estoy sorprendido de cómo el código de prueba hace que estas cosas sean evidentes, porque a menudo no pensaría en ellas. Si es difícil de probar, facilite la prueba. Generalmente ganas si haces eso.

+0

Amen. Escribir pruebas unitarias (o planear para ellas si hace TDD, ya sea que lo sepa o no) muy a menudo resulta en mejoras de diseño marcadas. – DVK

Cuestiones relacionadas