Code Contracts
Somos desarrolladores, no futbolistas… los contratos están para cumplirlos
Eduard Tomà[email protected]
www.codecamp.es
Algunas cosillas a comentar…
• Introducción• Precondiciones• Postcondiciones• Invariantes• Métodos puros (pero no castos)• Sandcastle!
www.codecamp.es
Introducción
• Que es Code Contracts?– Actualmente… un proyecto de Microsoft Research– http://research.microsoft.com/en-us/projects/con
tracts/
– En un futuro… Parte integral de .NET 4.0• Aunque… la beta1 de VS2010 tiene una versión
desactualizada
• Última versión (hasta ahora): 03 Sep 2009.
www.codecamp.es
Introducción
• Para qué sirve Code Contracts?– Librería para poder especificar contratos en .NET– Independiente del lenguaje (C#, F#, VB.NET)– Basada en atributos
– Se puede instalar sobre VS2008 o sobre VS2010 Beta 1
www.codecamp.es
Introducción
• La evaluación de contratos NO está activa por defecto– Puede habilitarse para DEBUG y/o RELEASE
• Solo precondiciones• Solo precondiciones y postcondiciones• Todo
• También podemos especificar el comportamiento por defecto– Assert o excepción Contract.Exception
www.codecamp.es
Introducción
• Contratos– Permiten especificar• Precondiciones
• Postcondiciones
• Invariantes de objeto
www.codecamp.es
Precondiciones
• Condiciones que la llamada a un método debe satisfacer
• Si no se cumplen la llamada no es válida– No debería compilar
• El llamante debe poder comprobar que su llamada cumple las precondiciones– Debe conocerlas… y poderlas comprobar!
www.codecamp.es
Precondiciones
• Se representan mediante la llamada al método Contract.Requires.
• Si la condición especificada en Requires no se cumple, la precondición no és válida…
• … Ya, y entonces… ¿qué ocurre?– Por defecto: Assert o excepción
www.codecamp.es
Precondiciones
• Contract.Requires(condición)– Assert o lanza Contract.Exception si la condición
no se cumple– Nota: Contract.Exception es interna.
• Contract.Requires<TEx>(condición)– Assert o lanza TEx si condición no se cumple
www.codecamp.es
Precondiciones
• Cuantificadores– Especificar Contratos sobre elementos de una
colección• ForAll -> Se cumple si todos los elementos de la
colección cumplen una condición• Exists -> Se cumple el contrato si un elemento de la
colección cumple la condición
– Pero… ya tenemos Linq!
www.codecamp.es
Postcondiciones
• Se evalúan cuando se retorna de un método– Puede retornarse de un método de dos maneres• Correctamente (return o fin)• Por error (excepción)
– Puede haber precondiciones distintas en función de si se sale correctamente o por error.
www.codecamp.es
Postcondiciones
• Métodos – Contract.Ensures– Contract.EnsuresOnThrow<TEx>
– Assert o lanzan excepción ContractException si la postcondición no se cumple
www.codecamp.es
Postcondiciones
• Postcondiciones se colocan al principio del método…
• … pero se evalúan cuando se sale del método
• Problema: Como acceder al valor de retorno?
www.codecamp.es
Postcondiciones
• No compila porque Ensures no está al principio del método
• … pero si lo pongo al principio NO PUEDO acceder a ret, porque no está definida!– Contract.ReturnValue<T >
int Foo(int i) { Contract.Requires(i >= 0); var ret = i + 1; Contract.Ensures(ret > 0); return ret; }
www.codecamp.es
Invariantes
• La invariante es un conjunto de condiciones que deben cumplirse siempre en el ciclo de vida de un objeto
• Las invariantes se comprueban después de cada llamada a un método público del objeto
www.codecamp.es
Invariantes
• Se definen un método decorado con el atributo [ContractInvariantMethod]
– Lista de llamadas a Contract.Invariant con las condiciones a cumplir
www.codecamp.es
Interfaces
• Las interfaces pueden definir contratos– Las interfaces no pueden tener código…– … donde ponemos las llamadas a Contract?– En cada clase?• No porque entonces el contrato sería de cada clase, no
de la interfaz!
– Solución• Clase de contratos
www.codecamp.es
Interfaces
• Clase de contratos– Clase que implementa una interfaz de forma
explícita y contiene sólo los contratos para la interfaz
– Clases que implementan la interfaz no deben redefinir los contratos…
– Atributos [ContractClass] y [ContractClassFor] sirven para identificar la clase de contrato
www.codecamp.es
Métodos puros
• Un método puro es un método que no tiene efectos laterales visibles para el llamante– No modifican el estado del objeto
• Contract.Requires y Contract.Ensures pueden llamar a métodos, pero deben ser siempre métodos puros.
www.codecamp.es
Métodos puros
• Se consideran métodos puros– Getters de propiedades– Operadores– Cualquier método que pertenezca a las clases de• System.Diagnostics.Contracts.Contract• System.String• System.IO.Path• System.Type
– Cualquier método decorado con [Pure]
www.codecamp.es
Herencia de contratos
• Si una clase B es derivada de A los contratos definidos en A se aplican a B, y…
– Los métodos redefinidos en B no pueden añadir precondiciones
– Los métodos redefinidos en B si pueden añadir postcondiciones
– Los invariantes se heredan (en la clase B se comprueban los de A y B automáticamente).
www.codecamp.es
Análisis estático
• Existe una herramienta que realiza análisis estático de los contratos– Es una tarea compleja, y la mayoría de contratos
no pueden comprobarse en tiempo de compilación
www.codecamp.es
Custom Rewriter
• Usar un custom rewriter permite cambiar el comportamiento cuando un contrato no se cumple…– ... P.ej. Guardarlo en un log
• El custom rewriter es una clase estática pública que debe contener determinados métodos– Desde VS podemos indicar que custom rewriter
usar
www.codecamp.es
Custom Rewriter
• Métodos “comunes”– Requires -> Se ejecuta cuando se evalúa un
Requires– Requires<E> -> Se ejecuta cuando se evalúa un
Requires y no se lanzan Asserts– ReportFailure -> Se ejecuta cuando falla una
validación de contrato y debe reportarse el fallo
www.codecamp.es
Unit Tests y Contratos (i)
• Usar Contract.Requires y desmarcar la checkbox de Asserts – Se lanzarán ContractException– Poco interesante ya que• ContractException es privada, no podemos usar
[ExpectedException]
www.codecamp.es
Unit Tests y Contratos (ii)
• Usar Requires<TEx> en lugar de Requires– Podemos usar [ExpectedException] – Modificamos el comportamiento en run-time de
nuestros contratos – Funciona para precondiciones pero no para
postcondiciones ni invariantes
www.codecamp.es
Unit Tests y Contratos (iii)
• Usar ContractFailed– Evento que se lanza cuando falla un contrato– No modificamos el comportamiento en run-time
de nuestros contratos – Funciona para cualquier tipo de violación de
contrato
www.codecamp.es
Sandcastle
• Con la última versión (¡por fin!) podemos documentar los contratos!!!
• Code Contracts lleva un “parche” para SandCastle para entender nuevos tags xml relacionados con contratos…– <requires>, <ensures>, <pure>,….
¿Preguntas ?Estooo… pero facilillas, eh?? ;-)
Recuerda que en www.codecamp.es podrás encontrar todo el material de las sesiones del CodeCamp