Programación Basada en Contratos vs Prueba de Unidad

13

Soy un programador algo defensivo y un gran fanático de los Contratos de Código de Microsofts.

Ahora no siempre puedo usar C # y en la mayoría de los idiomas, la única herramienta que tengo son las aserciones. Así que generalmente termino con un código como este:

class
{       
    function()
    {   
         checkInvariants();
         assert(/* requirement */);

         try
         {
             /* implementation */
         }
         catch(...)
         {
              assert(/* exceptional ensures */);                  
         }
         finally
         {
              assert(/* ensures */);
              checkInvariants();
         }
    }

    void checkInvariants()
    {
         assert(/* invariant */);
    }
}

Sin embargo, este paradigma (o como quiera llamarlo) lleva a una gran cantidad de código de desorden.

He empezado a preguntarme si realmente vale la pena el esfuerzo y si la prueba de unidad adecuada ya cubriría esto.

    
pregunta ronag 09.12.2013 - 10:17

6 respuestas

14

No creo que debas considerarlo como "vs".
Como se mencionó en los comentarios de @Giorgio, los contratos de código son para verificar invariantes (en el entorno de producción) y las pruebas unitarias son para asegurarse de que el código funciona como se espera cuando se cumplen esas condiciones.

    
respondido por el duros 09.12.2013 - 15:38
6

Los contratos lo ayudan con al menos una cosa que las pruebas de unidad no. Cuando está desarrollando una API pública, no puede hacer una prueba unitaria de cómo las personas usan su código. Sin embargo, aún puede definir contratos para sus métodos.

Yo personalmente sería tan riguroso con los contratos solo al tratar con la API pública de un módulo. En muchos otros casos, probablemente no valga la pena el esfuerzo (y en su lugar puedes usar pruebas de unidad), pero esto es solo mi opinión.

Eso no significa que aconseje no pensar en contratos en esos casos. Siempre pienso en ellos. Simplemente no creo que sea necesario codificarlos siempre explícitamente.

    
respondido por el Honza Brabec 09.12.2013 - 15:47
1

Como ya se mencionó, los contratos y las pruebas unitarias tienen un propósito diferente.

Los contratos se refieren a la programación defensiva para garantizar que se cumplan los requisitos previos, se llame al código con los parámetros correctos, etc.

Pruebas unitarias para garantizar que el código funciona, en diferentes escenarios. Estas son como 'especificaciones con dientes'.

Las afirmaciones son buenas porque hacen que el código sea robusto. Sin embargo, si le preocupa que se esté agregando una gran cantidad de código, es posible que también desee agregar puntos de interrupción condicionales en algunos lugares durante la depuración y reducir el recuento de afirmaciones.

    
respondido por el Sajad Deyargaroo 09.12.2013 - 16:51
0

Todo lo que tenga en sus llamadas checkVariants () se puede hacer desde las pruebas, el esfuerzo que realmente puede depender de muchas cosas (dependencias externas, niveles de acoplamiento, etc.) pero limpiaría el código desde un punto de vista. Lo verificable que sería una base de código desarrollada contra aserciones sin una refactorización, no estoy seguro.

Estoy de acuerdo con @duros, estos no deberían considerarse como enfoques exclusivos o competitivos. De hecho, en un entorno TDD, incluso se podría argumentar que las afirmaciones de 'requisito' serían necesarias para tener pruebas :).

Sin embargo, las afirmaciones

NO hacen que el código sea más sólido a menos que realmente haga algo para corregir la comprobación fallida, simplemente evitan que los datos se corrompan o sean similares, generalmente al abortar el procesamiento al primer signo de problemas.

Por lo general, una solución basada en pruebas / bien probada ya habrá pensado y / o descubierto muchas de las fuentes / razones de las entradas y salidas incorrectas al desarrollar los componentes que interactúan y ya los trató más cerca de la fuente del problema.

Si su fuente es externa y no tiene control sobre ella, entonces, para evitar saturar su código y tratar otros problemas de códigos, podría considerar implementar algún tipo de componente de depuración / confirmación de datos entre la fuente y su componente y colocar su cheques allí.

También tengo curiosidad por saber qué lenguajes usas que no tienen algún tipo de xUnit u otra biblioteca de pruebas que alguien haya desarrollado, ¿pensé que había algo para todo en estos días?

    
respondido por el Chris Lee 10.12.2013 - 21:36
0

Además de las pruebas unitarias y los contratos de código, simplemente pensé que destacaría otro aspecto, que es el valor en la definición de sus interfaces, de manera que elimine o reduzca la posibilidad de llamar su código incorrectamente en primer lugar.

No siempre es fácil o posible, pero definitivamente vale la pena preguntarse: "¿Puedo hacer que este código sea más infalible?"

Anders Hejlsberg, creador de C #, dijo que uno de los errores más grandes en C # no incluía tipos de referencia no anulables. Es una de las razones principales por la que existe el desorden de códigos de guardias necesarios.

Aún así, refactorizar para tener solo la cantidad necesaria y suficiente de código de guarda hace, en mi experiencia, un código más utilizable y mantenible.

De acuerdo con @duros en el resto de la misma.

    
respondido por el James World 11.12.2013 - 07:14
0

Haz ambas cosas, pero crea algunos métodos de ayuda estática para aclarar tus intenciones. Esto es lo que Google hizo para Java, visita code.google.com/p/guava-libraries/wiki/PreconditionsExplained

    
respondido por el Alexander Torstling 11.12.2013 - 08:00

Lea otras preguntas en las etiquetas