jueves, 22 de octubre de 2009

Code Contracts, Pruebas Unitarias y SandCastle (y los materiales del CodeCamp)

Buenas! Como prometí en el post anterior sobre el CodeCamp, en mi charla sobre Code Contracts, quedaron por ver algunos temillas que aprovecho para comentar ahora.

Pruebas Unitarias

Primero remarcar que no realiceis pruebas unitarias para validar que vuestros contratos están bien, es decir, si teneis un método:

public void Foo(int arg)
{
Contract.Requires(arg > 0);
}





No hagáis una prueba unitaria que compruebe que el contracto falla si se le pasa cero a arg.



¿Por qué no hacer esta prueba? Pues por dos razones.



La primera es “filosófica”: Un contrato fallado significa código erróneo, y no tiene sentido que una prueba unitaria que es código erróneo funcione correctamente.



La segunda es más práctica: Qué va a suceder cuando el contrato falle? Code Contracts dos modos de funcionamiento (se realiza un Asert, o bien se lanza una excepción), pero podemos añadir nuestro propio comportamiento. Además la prueba unitaria no debería asumir nada en cuanto al comportamiento de Code Contracts, ya que ese es variable por configuración (recordad que incluso podríamos tener todos los contratos deshabilitados en Release).



Si un contrato se rompe durante la ejecución de la prueba unitaria, la prueba debería fallar, con independencia del comportamiento en que tengamos configurado Code Contracts. Para ello puede usarse el evento ContractFailed, de la clase Contract, que se lanza cada vez que un contrato se rompe. El siguiente código lo podéis usar a tal efecto:




/* Convierte los fallos de contrato en fallos de Tests */
[AssemblyInitialize]
public static void AssemblyInitialize(TestContext tc)
{
Contract.ContractFailed += (sender, e) =>
{
e.SetHandled();
e.SetUnwind();
Assert.Fail(e.FailureKind.ToString() + ":" + e.Message);
};
}





Nos suscribimos al evento ContractFailed y en él:




  1. Indicamos a Code Contracts que no realice el comportamiento por defecto. P.ej. si Code Contracts estaba configurada para lanzar una excepción evitamos que la lance.


  2. Fallamos la prueba unitaria (mostrando cual es el contrato fallado).



De esta manera podéis “olvidaros” de Code Contracts y realizar pruebas unitarias que verifiquen vuestro código en lugar de los contratos, con la total seguridad de que si en cualquier momento un contrato falla, la prueba unitaria os lo verificará!



Sandcastle



Sandcastle es la herramienta para generar archivos de ayuda a partir de los comentarios XML en código fuente. No es excesivamente agradable de utilizar, aunque por suerte existe SandCastle Help File Builder, una GUI sobre Sandcastle que convierte su uso en casi trivial (si lo usáis sabed que puede integrarse con Team Build).



Los contratos son un elemento fundamental de los métodos y de una clase, pero sandcastle no los soporta (la última versión de sandcastle es mayo del 2008). Code contracts viene con un parche para sandcastle que se instala encima de sandcastle y que añade soporte para contratos. Con este parche instalado, podemos utilizar nuevas etiquetas xml, en nuestra documentación:




/// <summary>
/// Construye la pila de un tamaño máximo indicado.
/// </summary>
/// <param name="size">Tamaño máximo</param>
/// <requires />
public Pila(int size)
{
Contract.Requires(size > 0, "Tamaño inicial mayor que cero");
// Código...
}





P.ej. en este caso la etiqueta <requires /> indica que queremos documentar las precondiciones de este método. Luego en código utilizamos una sobrecarga de Contract.Requires que permite especificar un mensaje. Este mensaje es el que usa cuando falla el contrato, y también es el que usará sandcastle. Si no ponemos la etiqueta <requires /> las precondiciones no se documentarán aunque existan llamadas a Contract.Requires. Si alguien se pregunta porqué, es lo mismo que ocurre con el resto de documentación. P.ej. si no ponemos una etiqueta <param> no se documenta un parámetro de método, aunque éste exista.



El resultado será algo parecido a lo siguiente:



image



Como se puede observar se incluye un apartado “Contracts” con las precondiciones. Igual que existe la etiqueta <requires /> existen otras como <ensures /> para las postcondiciones,… Están todas ellas documentadas en el manual de Code Contracts.



Y el material del CodeCamp…



Aunque se lo mandaré a la organización para que lo cuelguen en la web del codecamp os dejo aquí el enlace al material de mi charla del codecamp. Son varias demos, que se auto-explican bastante y el ppt usado. Para cualquier duda… ya sabéis donde encontrarme!



 



Saludos!



PD: Crossposting desde mi blog en geeks.ms (acaso lo dudabas? ;-))

No hay comentarios: