Bienvenidos sean a este post, hoy veremos las distintas formas de correr un test.
Hasta ahora hemos visto como es la anatomia de un test, algunas macros y atributos para poder escribir nuestros test y ver si funcionan o no dependiendo de lo que vamos a verificar, en todos los casos usamos el siguiente comando:
$ cargo test
Pero podemos utilizar mas opciones y para ello debemos hacerlo de la siguiente forma:
$ cargo test -- opciones
Para entender este concepto y otros vamos a aplicar en un pequeño ejemplo, para ello tomaremos el codigo generado en el post anterior, en caso de no tenerlo simplemente generen una nueva libreria llamada invitados, y en este modificaremos el codigo del archivo lib.rs de la siguiente manera:
lib.rs
pub struct Invitado {
valor: u32,
}
impl Invitado
{
pub fn nuevo(valor: u32) -> Invitado {
if valor < 20
{
panic!("El id debe ser mayor a 20, pasaste {}", valor);
} else if valor > 70 {
panic!("El id debe ser menor a 70, pasaste {}", valor);
}
println!("El id es {}", valor);
Invitado { valor }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn crear_invitado()
{
Invitado::nuevo(40);
}
#[test]
fn crear_mal_invitado()
{
Invitado::nuevo(10);
}
}
Aqui tenemos un codigo que genera un id de invitado para una empresa X, en este caso tenemos un simple struct para el invitado, una implementacion que genera el nuevo invitado, en caso de que el id no este entre los valores 20 y 70 llamara a panic con dos mensajes distintos, uno para el caso de que sea menor a 20 y otro para mayor a 70, en este caso a diferencia del post anterior mostraremos el valor del id por medio de un println (ya veremos porque) y si paso los condicionales genera un objeto y lo devuelve, despues tendremos en el mod dos funciones para hacer testing, en la prmera se creara un invitado de manera correcta y en el segundo no, vamos a realizar el primer test pero con la siguiente variante:
$ cargo test -- --test-threads=1
Observen como utilizamos la sintaxis anteriormente descriptas, en este caso usamos una opcion para indicar que utilice un solo thread para hacer el test, esto hara que sea mas lento pero sera mas seguro, el resultado sera como cualquier otro test que hemos hecho hasta ahora:
tinchicus@dbn001vrt:~/lenguajes/rust/invitados$ cargo test -- --test-threads=1
warning: field is never read: `valor`
--> src/lib.rs:2:2
|
2 | valor: u32,
| ^^^^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: `invitados` (lib) generated 1 warning
warning: `invitados` (lib test) generated 1 warning (1 duplicate)
Finished test [unoptimized + debuginfo] target(s) in 0.02s
Running unittests (target/debug/deps/invitados-06ae58bb5146574f)
running 2 tests
test tests::crear_invitado ... ok
test tests::crear_mal_invitado ... FAILED
failures:
---- tests::crear_mal_invitado stdout ----
thread 'main' panicked at 'El id debe ser mayor a 20, pasaste 10', src/lib.rs:10:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
tests::crear_mal_invitado
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass '--lib'
tinchicus@dbn001vrt:~/lenguajes/rust/invitados$
Hasta aca nada del otro mundo, el aviso de que no usamos a la propiedad en ningun momento, la funcion que paso Ok y la falla de la funcion que no iba a funcionar, pero si observan no nos mostro la llamada al println, pero si nosotros necesitamos ver esto podemos usar una opcion para que no capture esto y lo muestre, para ello debemos correr el test con la siguiente opcion:
$ cargo test -- --nocapture
Tal como dijimos siempre usamos la misma sintaxis inicial y luego le agregamos el nocapture, con esto probemos de correr el test con esta nueva opcion y veamos que sucede:
Finished test [unoptimized + debuginfo] target(s) in 0.02s
Running unittests (target/debug/deps/invitados-06ae58bb5146574f)
running 2 tests
test tests::crear_invitado ... El id es 40
ok
test tests::crear_mal_invitado ... thread 'main' panicked at 'El id debe ser mayor a 20, pasaste 10', src/lib.rs:10:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
FAILED
failures:
failures:
tests::crear_mal_invitado
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass '--lib'
tinchicus@dbn001vrt:~/lenguajes/rust/invitados$
Observemos el primer detalle, el test que funciona correctamente llego a mostrar el valor que asignamos como id, en el segundo caso no porque entra en panico y sale del test pero tenganlo en cuenta que nos puede servir para hacer una depuracion, dado que si queremos saber que esta haciendo durante el test o ver los distintos valores que maneja podemos usar varios println mostrando lo que necesitemos y por medio de nocapture lo veremos en la salida del test.
Hasta ahora siempre que corrimos un test nos lo hacia en todas las funciones que agregamos el atributo test pero en algunas ocasiones no necesitaremos analizar todas las funciones sino simplemente la que falla o alguna en particular, para ello simplemente debemos pasar la funcion que deseamos chequear, veamos un ejemplo:
$ cargo test crear_invitado
Si lo corremos veremos la sigueinte salida:
Finished test [unoptimized + debuginfo] target(s) in 0.02s
Running unittests (target/debug/deps/invitados-06ae58bb5146574f)
running 1 test
test tests::crear_invitado ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s
tinchicus@dbn001vrt:~/lenguajes/rust/invitados$
Como podemos ver el test corrio exitosamente dado que ahora no hicimos el test sobre la funcion que falla sino solamente sobre la unica que hace lo que debe hacer, observen que nos comenta que dejo uno filtrado (filtered out), si hubiera mas funciones figurarian ahi, pero tambien podemos filtrar por solo una porcion del nombre, por ejemplo:
$ cargo test mal
En este caso no tenemos una funcion que se llame mal pero si una que posee esta palabra, cargo entiende que debe procesar todas las funciones que posean esta palabra, por lo tanto tendremos una salida como la siguiente:
Finished test [unoptimized + debuginfo] target(s) in 0.01s
Running unittests (target/debug/deps/invitados-06ae58bb5146574f)
running 1 test
test tests::crear_mal_invitado ... FAILED
failures:
---- tests::crear_mal_invitado stdout ----
thread 'main' panicked at 'El id debe ser mayor a 20, pasaste 10', src/lib.rs:10:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
tests::crear_mal_invitado
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s
error: test failed, to rerun pass '--lib'
tinchicus@dbn001vrt:~/lenguajes/rust/invitados$
En esta salida proceso a la funcion que falla y por lo tanto fallo el test y observen que volvio a filtrar una funcion, con esto ya casi tenemos todo pero nos falta un atributo mas.
Este atributo es ignore y como su nombre lo indica es para ignorar un test, esta pensado para cuando ya sabemos que determinados test pasan sin problemas y no necesitamos correrlo pero no queremos quitar la etiqueta porque mas adelante puede que necesitemos correrlo nuevamente, aqui entra este atributo en accion, vamos a modificar la funcion que falla de la siguiente forma:
#[test]
#[ignore]
fn crear_mal_invitado()
{
Invitado::nuevo(10);
}
Simplemente agregaremos el atributo despues del test, con esto solo ya el compilador se encargara de ignorarlo al momento de correr el test, corramos el test para ver como funciona:
Finished test [unoptimized + debuginfo] target(s) in 1.20s
Running unittests (target/debug/deps/invitados-06ae58bb5146574f)
running 2 tests
test tests::crear_invitado ... ok
test tests::crear_mal_invitado ... ignored
test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests invitados
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
tinchicus@dbn001vrt:~/lenguajes/rust/invitados$
Nota: Para correr este test simplemente corran a cargo test como siempre.
Observen que el primero paso Ok y el segundo fue … ignored, tal como esperabamos pero vemos que no tuvimos ninguna falla sino solamente el pasado y el ignorado, con esto y tenemos una buena base para poder correr nuestros test de manera mas especifica, ya sea para correrlos en uno o varios threads, asi como que nos muestre algun mensaje que hayamos agregado, tambien como filtrar una o varias funciones asi como la posibilidad de ignorarlo.
En resumen, hoy hemos visto como correr un test con varias opciones, hemos visto las distintas opciones que disponemos para poder moldear la salida a nuestra necesidad, hemos visto algunas opciones como tambien atributos para formatear la salida, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
