t
.
$ pwd /home/lhp/Lperl/src/threads/knapsack/Algorithm-Knap01DP/t $ ls -l -rw-r--r-- 1 lhp lhp 1693 2005-05-17 19:57 01MartelloAndTothBook.t -rw-r--r-- 1 lhp lhp 134 2005-05-16 18:37 knap21.dat -rw-r--r-- 1 lhp lhp 125 2005-05-16 18:37 knap22.dat -rw-r--r-- 1 lhp lhp 123 2005-05-16 18:37 knap23.dat -rw-r--r-- 1 lhp lhp 158 2005-05-16 18:37 knap25.datAdemás del programa
01MartelloAndTothBook.t
tenemos cuatro ficheros
con cuatro diferentes problemas de la mochila. Los números corresponden
a las páginas del clásico libro de Martello y Toth [13]
en el que aparece el correspondiente
problema.
$ cat -n 01MartelloAndTothBook.t 1 # Before `make install' is performed this script should be runnable with 2 # `make test'. After `make install' it should work as `perl Algorithm-Knap01DP.t' 3 4 ######################### 5 use strict; 6 use Test::More tests => 11; 7 8 BEGIN { use_ok('Algorithm::Knap01DP', qw/Knap01DP ReadKnap/); }
Realizaremos 11 pruebas de las que la primera es comprobar que el módulo se carga correctamente (línea 8).
10 ### main 11 my @inputfiles = qw/knap21.dat knap22.dat knap23.dat knap25.dat/; 12 my @sol = (280, 107, 150, 900); 13 my $knap21 = ['102', [ '2', '20', '20', '30', '40', '30', '60', '10' ], 14 [ '15', '100', '90', '60', '40', '15', '10', '1' ]]; 15 my $knap22 = ['50', [ '31', '10', '20', '19', '4', '3', '6' ], 16 [ '70', '20', '39', '37', '7', '5', '10' ]]; 17 my $knap23 = ['190', [ '56', '59', '80', '64', '75', '17' ], 18 [ '50', '50', '64', '46', '50', '5' ]]; 19 my $knap25 = ['104', [ '25', '35', '45', '5', '25', '3', '2', '2' ], 20 [ '350', '400', '450', '20', '70', '8', '5', '5' ]]; 21 22 my $knapsackproblem = [$knap21, $knap22, $knap23, $knap25];La variable
@inputfiles
contiene los nombres de los ficheros
de prueba. La variable @sol
las soluciones óptimas a esos
problemas. Las variables $knap21
...$knap25
contienen
estructuras de datos que definen los problemas: capacidad de la mochila, vector de pesos
y vector de beneficios. Cuando la función ReadKnap
lee un fichero
de datos devuelve una estructura como esta:
~/Lperl/src/threads/knapsack/Algorithm-Knap01DP/t$ perl \ -I/home/lhp//Lperl/src/threads/knapsack/Algorithm-Knap01DP/lib \ -d 01MartelloAndTothBook.t Loading DB routines from perl5db.pl version 1.25 1..11 ok 1 - use Algorithm::Knap01DP qw/Knap01DP ReadKnap/;; main::(01MartelloAndTothBook.t:11): 11: my @inputfiles = qw/knap21.dat knap22.dat knap23.dat knap25.dat/; DB<1> b 31 # ponemos un break después de la llamada a ReadKnap DB<2> c # y ejecutamos hasta allí main::(01MartelloAndTothBook.t:31): 31: is_deeply($knapsackproblem->[$i], [$M, $w, $p], "ReadKnap $file"); DB<2> x [$M, $w, $p] # Veamos que nos devuelve ReadKnap: 0 ARRAY(0x8555ad0) 0 102 1 ARRAY(0x845e034) 0 2 1 20 2 20 3 30 4 40 5 30 6 60 7 10 2 ARRAY(0x845e04c) 0 15 1 100 2 90 3 60 4 40 5 15 6 10 7 1De hecho, es usando el depurador, cortando y pegando que hemos construido las líneas 13-20 definiendo las estructuras de datos
$knapXX
.
A continuación leeemos cada fichero y comprobamos que ambas ReadKnap
y Knap01DP
dan los resultados esperados. La función
is_deeply
nos dice si dos estructuras de datos son equivalentes.
Véase perldoc Test::More
para mas información sobre
el módulo Test::More y las funciones is_deeply
e is
.
24 my $i = 0; 25 my ($M, $w, $p); 26 my @f; 27 28 # Now 2*@inputfiles = 8 tests 29 for my $file (@inputfiles) { 30 ($M, $w, $p) = ReadKnap((-e "t/$file")?"t/$file":$file); 31 is_deeply($knapsackproblem->[$i], [$M, $w, $p], "ReadKnap $file"); 32 my $N = @$w; 33 @f = Knap01DP($M, $w, $p); 34 is($sol[$i++], $f[$N-1][$M], "Knap01DP $file"); 35 }A continuación realizamos una prueba para comprobar el funcionamiento cuando se le pasan a
Knap01DP
vectores de pesos y beneficios de
distinto tamaño. Recordemos que en la rutina Knap01DP
habíamos
escrito el siguiente código:
22 croak "Profits and Weights don't have the same size" unless scalar(@w) == scalar(@p)por tanto, pasarle a la rutina vectores de distinto tamaño hace que el programa muera. Es por esto que protegeremos la ejecución dentro de un
eval
:
37 # test to check when weights and profits do not have the same size 38 $M = 100; @$w = 1..5; @$p = 1..10; 39 eval { Knap01DP($M, $w, $p) }; 40 like $@, qr/Profits and Weights don't have the same size/;Observe las salidas y los comentarios en inglés. Si tu intención es hacer público el módulo en CPAN es recomendable que las salidas, los nombres de variables y los comentarios estén en ese idioma.
Vamos a hacer una prueba mas. Supongamos que tengo la intención de
añadir una función GenKnap
que genere aleatoriamente un problema de
la mochila. Como no esta hecho,
lo declaramos como una prueba a hacer (TODO). Es decir, se trata de un
test que fallará, pero que se espera que deje de hacerlo en el futuro.
42 TODO: { # I plan to provide a function to find the vector solution ... 43 local $TODO = "Return vector solution"; 44 can_ok('Algorithm::Knap01DP', 'GenKnap'); 45 }Primero una ejecución a mano:
~/Lperl/src/threads/knapsack/Algorithm-Knap01DP/t$ perl \ -I/home/lhp//Lperl/src/threads/knapsack/Algorithm-Knap01DP/lib 01MartelloAndTothBook.t 1..11 ok 1 - use Algorithm::Knap01DP qw/Knap01DP ReadKnap/;; ok 2 - ReadKnap knap21.dat ok 3 - Knap01DP knap21.dat ok 4 - ReadKnap knap22.dat ok 5 - Knap01DP knap22.dat ok 6 - ReadKnap knap23.dat ok 7 - Knap01DP knap23.dat ok 8 - ReadKnap knap25.dat ok 9 - Knap01DP knap25.dat ok 10 not ok 11 - Algorithm::Knap01DP->can('GenKnap') # TODO Randomly generated problem # Failed (TODO) test (01MartelloAndTothBook.t at line 45) # Algorithm::Knap01DP->can('GenKnap') failedObsérvese que:
t
.
-I
para que pueda encontrar el módulo.
not ok 11 - ... # TODO Return ...
indicando que falla y que es una prueba TODO
.
make test
(un directorio por encima):
~/Lperl/src/threads/knapsack/Algorithm-Knap01DP$ make test PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" \ "-e" "test_harness(0, 'blib/lib', 'blib/arch')" \ t/*.t t/01MartelloAndTothBook....ok All tests successful. Files=1, Tests=11, 0 wallclock secs ( 0.09 cusr + 0.00 csys = 0.09 CPU)Observa como ahora se informa que todas las pruebas fueron correctamente. Se ha ocultado que hay una prueba
TODO
y su fallo no se considera significativo para
la posible instalación del módulo. De este modo el directorio
de pruebas puede ser utilizado como lista recordatorio de objetivos
y requerimientos a realizar.