¿Hay alguna razón por la que las pruebas no se escriban en línea con el código que prueban?

90

Recientemente he estado leyendo un poco sobre Literate Programming , y me puse a pensar ... Bien escrito Las pruebas, especialmente las especificaciones de estilo BDD, pueden hacer un mejor trabajo para explicar qué hace el código que la prosa y tienen la gran ventaja de verificar su propia precisión.

Nunca he visto pruebas escritas en línea con el código que prueban. ¿Esto se debe a que los idiomas no tienden a simplificar la separación de la aplicación y el código de prueba cuando se escriben en el mismo archivo fuente (y nadie lo ha facilitado), o existe una razón más basada en que las personas separan el código de prueba del código de la aplicación?

    
pregunta Chris Devereux 25.02.2013 - 14:28

12 respuestas

89

La única ventaja que puedo imaginar para las pruebas en línea sería reducir la cantidad de archivos que se escribirán. Con los IDE modernos, esto realmente no es tan importante.

Sin embargo, existen varios inconvenientes obvios en las pruebas en línea:

  • Viola la separación de inquietudes . Esto puede ser discutible, pero para mí, probar la funcionalidad es una responsabilidad diferente a su implementación.
  • Tendrías que introducir nuevas características de lenguaje para distinguir entre pruebas / implementación, o te arriesgarías a desdibujar la línea entre las dos.
  • Es más difícil trabajar con archivos de origen más grandes: más difícil de leer, más difícil de entender, es más probable que tenga que lidiar con los conflictos de control de origen.
  • Creo que sería más difícil ponerse el sombrero de "probador", por así decirlo. Si está viendo los detalles de la implementación, estará más tentado a omitir la implementación de ciertas pruebas.
respondido por el vaughandroid 25.02.2013 - 15:15
36

Puedo pensar en algunas:

  • Legibilidad. Intercalar código y pruebas "reales" hará que sea más difícil leer el código real.

  • Código inflado. Mezclar código "real" y código de prueba en los mismos archivos / clases / lo que sea probable que resulte en archivos compilados más grandes, etc. Esto es particularmente importante para los idiomas con enlace tardío.

  • Es posible que no desee que sus clientes vean su código de prueba. (No me gusta como esta razón ... pero si está trabajando en un proyecto de código cerrado, es poco probable que el código de prueba ayude al cliente).

Ahora hay posibles soluciones para cada uno de estos problemas. Pero en mi opinión, es más sencillo no ir allí en primer lugar.

Vale la pena observar que en los primeros días, los programadores de Java solían hacer este tipo de cosas; p.ej. incluyendo un método main(...) en una clase para facilitar las pruebas. Esta idea ha desaparecido casi por completo. Es una práctica de la industria implementar pruebas por separado utilizando un marco de prueba de algún tipo.

También vale la pena observar que la Programación Literate (tal como fue concebida por Knuth) nunca se ha popularizado en la industria de la ingeniería de software.

    
respondido por el Stephen C 25.02.2013 - 14:38
13

Por muchas de las mismas razones por las que intenta evitar un acoplamiento estrecho entre clases en su código, también es una buena idea evitar un acoplamiento innecesario entre pruebas y código.

Creación: Las pruebas y el código pueden ser escritos en diferentes momentos, por diferentes personas.

Control: Si las pruebas se usan para especificar requisitos, seguramente querrá que estén sujetas a diferentes reglas sobre quién puede cambiarlas y cuándo es el código real.

Reutilización: Si coloca las pruebas en línea, no puede usarlas con otro código.

Imagina que tienes una parte del código que hace el trabajo correctamente, pero deja mucho que desear en términos de rendimiento, mantenimiento, lo que sea. Usted decide reemplazar ese código con un código nuevo y mejorado. El uso del mismo conjunto de pruebas puede ayudarlo a verificar que el nuevo código produce los mismos resultados que el código anterior.

Selección: Mantener las pruebas separadas del código facilita la elección de las pruebas que desea ejecutar.

Por ejemplo, es posible que tenga un pequeño conjunto de pruebas que se relacionen solo con el código en el que está trabajando actualmente, y un conjunto más grande que pruebe todo el proyecto.

    
respondido por el Caleb 25.02.2013 - 20:03
13

En realidad, puede pensar que Design By Contract hace esto. El problema es que la mayoría de los lenguajes de programación no le permiten escribir código como este :( Es muy fácil probar las condiciones previas a mano, pero las condiciones posteriores son un verdadero desafío sin cambiar la forma en que se escribe el código (un IMO muy negativo).

Michael Feathers tiene una presentación sobre esto y esta es una de las muchas maneras en que lo menciona Mejorar la calidad del código.

    
respondido por el Daniel Kaplan 21.03.2013 - 19:43
10

Aquí hay algunas razones adicionales que se me ocurren:

  • tener pruebas en una biblioteca separada hace que sea más fácil vincular solo esa biblioteca con su marco de prueba, y no con su código de producción (esto podría ser evitado por algún preprocesador, pero ¿por qué crear una cosa así cuando la solución es más fácil?) es escribir las pruebas en un lugar separado)

  • las pruebas de una función, una clase, una biblioteca se escriben normalmente desde el punto de vista de los "usuarios" (un usuario de esa función / clase / biblioteca). Dicho "código de uso" generalmente se escribe en un archivo o biblioteca por separado, y una prueba puede ser más clara o "más realista" si imita esa situación.

respondido por el Doc Brown 25.02.2013 - 15:14
5

Si las pruebas estuvieran en línea, sería necesario eliminar el código que necesita para realizar las pruebas cuando envíe el producto a su cliente. Por lo tanto, un lugar adicional donde almacena sus pruebas simplemente separa entre el código que necesita y el código que su cliente necesita.

    
respondido por el mrtnrdl 25.02.2013 - 14:38
4

Esto es en respuesta a una gran cantidad de comentarios que sugieren que las pruebas en línea no se realizan porque es difícil o imposible eliminar el código de prueba de las versiones de lanzamiento. Esto no es cierto. Casi todos los compiladores y ensambladores ya lo admiten, con lenguajes compilados, como C, C ++, C #, esto se hace con lo que se conoce como directivas de compilación.

En el caso de c # (también creo que c ++, la sintaxis puede ser ligeramente diferente según el compilador que estés usando), así es como puedes hacerlo.

#define DEBUG //  = true if c++ code
#define TEST /* can also be defined in the make file for c++ or project file for c# and applies to all associated .cs/.cpp files */

//somewhere in your code
#if DEBUG
// debug only code
#elif TEST
// test only code
#endif

Debido a que usa directivas de compilación, el código no existirá en los archivos ejecutables que se crean si no se establecen los indicadores. Esta es también la forma en que crea programas de "escritura una vez, compilación dos veces" para múltiples plataformas / hardware.

    
respondido por el john 04.05.2013 - 23:02
3

Esta idea simplemente equivale a un método "Self_Test" dentro del contexto de un diseño basado en objetos u orientado a objetos. Si utiliza un lenguaje compilado basado en objetos como Ada, el compilador marcará todo el código de autoprueba como no utilizado (nunca invocado) durante la compilación de producción, y por lo tanto todo se optimizará. No aparecerá ninguno en el ejecutable resultante.

Usar un método "Self_Test" es una muy buena idea, y si los programadores estuvieran realmente preocupados por la calidad, todos lo estarían haciendo. Sin embargo, un problema importante es que el método "Self_Test" debe tener una disciplina intensa, ya que no puede acceder a ninguno de los detalles de la implementación y, en cambio, debe confiar solo en todos los demás métodos publicados dentro de la especificación del objeto. Obviamente, si la autoprueba falla, la implementación deberá cambiar. La autoprueba debe probar rigurosamente todas las propiedades publicadas de los métodos del objeto, pero nunca depender de ningún modo de los detalles de una implementación específica.

Los lenguajes basados en objetos y orientados a objetos frecuentemente brindan exactamente ese tipo de disciplina con respecto a los métodos externos al objeto probado (imponen la especificación del objeto, impiden cualquier acceso a sus detalles de implementación y generan un error de compilación, si es que existe). intento es detectado). Pero a los propios métodos internos del objeto se les da acceso completo a cada detalle de implementación. Por lo tanto, el método de autoprueba se encuentra en una situación única: debe ser un método interno debido a su naturaleza (la autoprueba es obviamente un método del objeto que se está probando), pero necesita recibir toda la disciplina del compilador de un método externo ( tiene que ser independiente de los detalles de implementación del objeto). Pocos, si los hay, lenguajes de programación proporcionan la capacidad de disciplinar el método interno de un objeto como si fuera un método externo. Así que este es un importante problema de diseño de lenguaje de programación.

En ausencia de un soporte adecuado del lenguaje de programación, la mejor manera de hacerlo es crear un objeto complementario. En otras palabras, para cada objeto que codifiques (llamémoslo "Big_Object"), también creas un segundo objeto complementario cuyo nombre consiste en un sufijo estándar concatenado con el nombre del objeto "real" (en este caso, "Big_Object_Self_Test "), y cuya especificación consiste en un solo método (" Big_Object_Self_Test.Self_Test (This_Big_Object: Big_Object) return boolean; "). El objeto complementario dependerá de la especificación del objeto principal, y el compilador aplicará completamente toda la disciplina de esa especificación contra la implementación del objeto complementario.

    
respondido por el commenter8 04.05.2013 - 19:01
2

Usamos pruebas en línea con nuestro código Perl. Hay un módulo, Test :: Inline , que genera archivos de prueba a partir del código en línea.

No soy particularmente bueno organizando mis pruebas, y he encontrado que son más fáciles y más probables de mantener cuando están en línea.

Respondiendo a un par de las preocupaciones planteadas:

  • Las pruebas en línea están escritas en las secciones de POD, por lo que no forman parte del código real. El intérprete los ignora, por lo que no hay código inflado.
  • Utilizamos Vim fold para ocultar las secciones de prueba. Lo único que ve es una sola línea sobre cada método que se está probando como +-- 33 lines: #test---- . Cuando quiera trabajar con la prueba, simplemente amplíela.
  • El módulo Test :: Inline "compila" las pruebas en archivos normales compatibles con TAP, para que puedan coexistir con las pruebas tradicionales.

Para referencia:

respondido por el mla 04.05.2013 - 23:04
1

Erlang 2 realmente soporta pruebas en línea. Cualquier expresión booleana en el código que no se usa (por ejemplo, asignada a una variable o pasada) se trata automáticamente como una prueba y es evaluada por el compilador; si la expresión es falsa, el código no se compila.

    
respondido por el Mark Rendle 04.05.2013 - 21:38
1

Otra razón para separar las pruebas es que a menudo se usan bibliotecas adicionales o incluso diferentes para las pruebas que para la implementación real. Si combina pruebas e implementación, el compilador no puede detectar el uso accidental de las bibliotecas de prueba en la implementación.

Además, las pruebas tienden a tener más líneas de código que las partes de implementación que prueban, por lo que tendrá problemas para encontrar la implementación entre todas las pruebas. :-)

    
respondido por el Hans-Peter Störr 04.06.2013 - 10:52
0

Esto no es cierto. Es mucho mejor colocar las pruebas unitarias junto al código de producción cuando el código de producción, especialmente cuando la rutina de producción es pura.

Si está desarrollando bajo .NET, por ejemplo, puede poner su código de prueba en el ensamblaje de producción y luego usar Scalpel para eliminarlos antes de enviarlos.

    
respondido por el zumalifeguard 06.05.2016 - 23:07

Lea otras preguntas en las etiquetas