2011-03-02 15 views
6

Solo estoy jugando con los contratos de código en .NET 4.0 y me falta algo obvio, ya que no se comportan como era de esperar.Contratos de código de prueba unitaria

Siempre he usado una sentencia simple si ... then .. throw para realizar cualquier validación al inicio de una función.

if (hours < 0 || hours > 8) 
    throw new ArgumentOutOfRangeException("hours", "Hours must be between 0 and 8"); 

he sustituido simplemente esto con

Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8"); 

pero nunca parece arrojar un problema en mis pruebas de unidad.

public static DurationUnit HoursAsDuration(int hours) 
    { 
     Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8"); 

     switch (hours) 
     { 
      case 1: 
      case 2: 
       return DurationUnit.Quarter; 
      case 3: 
      case 4: 
       return DurationUnit.Half; 
      case 5: 
      case 6: 
       return DurationUnit.ThreeQuarter; 
      case 7: 
      case 8: 
       return DurationUnit.Full; 
      default: 
       return DurationUnit.None; 
     } 
    } 

    [Test] 
    public void CanConvertToDuration() 
    { 
     Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(0)); 
     Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(1)); 
     Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(2)); 
     Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(3)); 
     Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(4)); 
     Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(5)); 
     Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(6)); 
     Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(7)); 
     Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(8)); 

     //Would expect this to cause an issue 
     Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(9)); 
    } 

La prueba devuelve cierto, pero me habría esperado que el contrato de código para detener el valor de "9" entrar en la sentencia switch. Es este el comportamiento esperado?

Respuesta

1

Si la especificación de su función, expresada en inglés, acepta cualquier valor para hours y arroja una excepción cuando hours no está en el rango 0..8, entonces su contrato (expresado en lenguaje de Contratos de Código) no es requiere que hours esté entre 0 y 8. La traducción correcta es que la función no requiere nada, y garantiza que si hours estaba en el rango incorrecto, se ha producido una excepción, y se asegura de que si hours estaba en el rango correcto, se hizo el cálculo adecuado.

Esperaría que haya una forma de expresar estas cosas en Contratos de código, pero no estoy familiarizado con este lenguaje de contrato, solo con otro. Sin embargo, la filosofía es la misma: si desea que el cheque sea parte de la construcción de producción, entonces la condición del cheque no es una condición previa.Por otro lado, el contrato puede (debe) expresar que el cheque se ha realizado y que cada caso se maneja de manera apropiada.

+0

Gracias a Pascal que aclara un poco las cosas. Creía que los contratos de código podrían reemplazar todas las comprobaciones de parámetros, pero aún deberán permanecer si los quiero en la compilación de producción. – fluent

+0

Actualización: Porges a continuación me ha señalado en la dirección correcta al editar la configuración del proyecto para habilitar los contratos en la compilación de producción. – fluent

-1

Creo que debe cambiar las pruebas de su parámetro de horas.

Se supone que debe definir la regla que pasaría.

así que creo que esto funcionaría para usted ...

Contract.Requires<ArgumentOutOfRangeException>(hours < 0 && hours > 8, "Hours must be between 0 and 8"); 
+0

Gracias, detectaron un error en mi publicación que fue un poco engañoso. El original si ... entonces ... tiro fue incorrecto y ahora lo he corregido. Sin embargo, el problema aún existe. – fluent

+4

-1: Esto no tiene ningún sentido. En esencia, declara que "necesita" 'horas' para ser menor que cero y mayor que 8 al mismo tiempo. – Virtlink

0

Ok, ahora tengo el código de tirar el error esperado al permitir que el "Realizar tiempo de ejecución del contrato Comprobación" opción dentro de las propiedades del proyecto en Visual Studio .

¿Esto significa que cuando se lanza a producción, los contratos de código se ignoran efectivamente?

Obviamente no entiendo cómo se supone que se usan los contratos de código, de modo que si alguien pudiera indicarme un artículo de mejores prácticas, le agradecería.

la página de MSDN estados:

"La mayoría de los métodos de la clase de contrato están compilados de forma condicional, es decir, el compilador emite llamadas a estos métodos sólo cuando se define un símbolo especial, contratos COMPLETO, mediante el uso de la #define directivas. CONTRATOS COMPLETO le permite escribir contratos en su código sin usar las directivas #ifdef; puede producir versiones diferentes, algunas con contratos y otras sin ".

¿Esto significa que todavía sería mejor usarlo si ... entonces ... arrojar ... para cualquier cosa pública? Las comprobaciones de validación de parámetros realmente ayudan a reducir la corrupción de datos, ya que señala el punto de falla tan pronto como sea posible.

+0

Yo diría que "sí" para todas las preguntas en su respuesta, y ampliaría un poco, pero los comentarios de StackOverflow son un poco limitantes, así que escribí otra respuesta. –

+1

rggardner: hay muchas opciones en las propiedades del proyecto :) Puede habilitar el cumplimiento en tiempo de ejecución para una compilación de versión o deshabilitarla como lo desee. Depende de lo que quieras hacer con los Contratos. También puede habilitarlo solo en los métodos de cara al público, etc. – porges

+0

Gracias Porges, muy útil para saber. Todo lo que tengo que hacer ahora es trabajar la configuración correcta en mis archivos de compilación. – fluent

Cuestiones relacionadas