He estado leyendo un poco sobre programación literaria recientemente, y me hizo pensar ... Las pruebas bien escritas, especialmente las especificaciones de estilo BDD, pueden hacer un mejor trabajo al 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. ¿Es esto solo porque 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 hay una razón más basada en principios para que las personas separen el código de prueba del código de la aplicación?
testing
unit-testing
bdd
literate-programming
Chris Devereux
fuente
fuente
Respuestas:
La única ventaja que se me ocurre para las pruebas en línea sería la reducción de la cantidad de archivos que se escribirán. Con los IDEs modernos, esto realmente no es un gran problema.
Sin embargo, hay una serie de inconvenientes obvios para las pruebas en línea:
fuente
Puedo pensar en algunos:
Legibilidad. La intercalación de códigos y pruebas "reales" hará que sea más difícil leer el código real.
Código hinchado. Mezclar código "real" y código de prueba en los mismos archivos / clases / lo que sea probable que dé como resultado 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 / clientes vean su código de prueba. (No me gusta 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 de todos modos).
Ahora hay posibles soluciones para cada uno de estos problemas. Pero en mi opinión, es más simple 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; por ejemplo, incluir un
main(...)
método en una clase para facilitar las pruebas. Esta idea ha desaparecido casi por completo. Es 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 literaria (tal como la concibió Knuth) nunca ha tenido éxito en la industria de la ingeniería de software.
fuente
En realidad, puede pensar en Design By Contract como haciendo 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 de publicación son un verdadero desafío sin cambiar la forma en que escribe el código (una gran IMO negativa).
Michael Feathers tiene una presentación sobre esto y esta es una de las muchas formas en que menciona que puede mejorar la calidad del código.
fuente
Por muchas de las mismas razones por las que intenta evitar el acoplamiento estrecho entre clases en su código, también es una buena idea evitar el acoplamiento innecesario entre las pruebas y el código.
Creación: las pruebas y el código pueden ser escritos en diferentes momentos, por diferentes personas.
Control: si se utilizan pruebas 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.
Reusabilidad: si coloca las pruebas en línea, no puede usarlas con otro código.
Imagine que tiene una porción de código que hace el trabajo correctamente, pero deja mucho que desear en términos de rendimiento, mantenibilidad, lo que sea. Decide reemplazar ese código con código nuevo y mejorado. Usar el mismo conjunto de pruebas puede ayudarlo a verificar que el nuevo código produzca los mismos resultados que el código anterior.
Posibilidad de selección: mantener las pruebas separadas del código facilita la elección de las pruebas que desea ejecutar.
Por ejemplo, puede tener un pequeño conjunto de pruebas que se relacionan solo con el código en el que está trabajando actualmente, y un conjunto más grande que prueba todo el proyecto.
fuente
Aquí hay algunas razones adicionales en las que puedo pensar:
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é construir tal cosa cuando la solución más fácil es escribir las pruebas en un lugar separado)
Las pruebas de una función, una clase, una biblioteca generalmente se escriben desde el punto de vista de "usuarios" (un usuario de esa función / clase / biblioteca). Dicho "uso de código" generalmente se escribe en un archivo o biblioteca separados, y una prueba puede ser más clara o "más realista" si imita esa situación.
fuente
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 se separa entre el código que necesita y el código que necesita su cliente .
fuente
Esta idea simplemente equivale a un método "Self_Test" dentro del contexto de un diseño orientado a objetos o basado en objetos. Si utiliza un lenguaje compilado basado en objetos como Ada, el compilador marcará todo el código de autocomprobación como no utilizado (nunca invocado) durante la compilación de producción y, por lo tanto, todo se optimizará, ninguno aparecerá 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, una cuestión importante es que el método "Self_Test" debe tener una disciplina intensa, ya que no puede acceder a ninguno de los detalles de implementación y en su lugar debe confiar únicamente en todos los demás métodos publicados dentro de la especificación del objeto. Obviamente, si la autocomprobación falla, la implementación deberá cambiar. La autocomprobación debe probar rigurosamente todas las propiedades publicadas de los métodos del objeto, pero nunca depender de ningún modo de ningún detalle de una implementación específica.
Los lenguajes basados en objetos y orientados a objetos con frecuencia proporcionan exactamente ese tipo de disciplina con respecto a los métodos externos al objeto probado (hacen cumplir la especificación del objeto, impiden el acceso a los detalles de su implementación y generan un error de compilación si se detecta cualquier intento de este tipo). ) Pero todos los métodos internos del objeto tienen acceso completo a cada detalle de implementación. Por lo tanto, el método de autocomprobación se encuentra en una situación única: debe ser un método interno debido a su naturaleza (la autocomprobación 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 lenguajes de programación ofrecen la capacidad de disciplinar un objeto ' s método interno como si fuera un método externo. Así que este es un problema importante de diseño del lenguaje de programación
En ausencia de un soporte de lenguaje de programación adecuado, la mejor manera de hacerlo es crear un objeto complementario. En otras palabras, para cada objeto que codifique (llamémoslo "Big_Object"), también crea 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 único método (" Big_Object_Self_Test.Self_Test (This_Big_Object: Big_Object) return Boolean; "). El objeto complementario dependerá entonces 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.
fuente
Esto es en respuesta a una gran cantidad de comentarios que sugieren que no se realizan pruebas en línea 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 las llamadas directivas de compilación.
En el caso de C # (también creo que C ++, la sintaxis podría haber sido ligeramente diferente dependiendo del compilador que esté usando) así es como puede hacerlo.
Debido a que utiliza directivas de compilación, el código no existirá en los archivos ejecutables que se crean si no se establecen los indicadores. Así es también como se hacen programas de "escribir una vez, compilar dos veces" para múltiples plataformas / hardware.
fuente
Utilizamos 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 es más fácil y más probable que se mantengan cuando están en línea.
Respondiendo a un par de preocupaciones planteadas:
+-- 33 lines: #test----
. Cuando desee trabajar con la prueba, simplemente amplíela.Para referencia:
fuente
Erlang 2 en realidad admite pruebas en línea. Cualquier expresión booleana en el código que no se utiliza (por ejemplo, asignada a una variable o aprobada) se trata automáticamente como una prueba y el compilador la evalúa; Si la expresión es falsa, el código no se compila.
fuente
Otra razón para separar las pruebas es que a menudo utiliza 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 muchas 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. :-)
fuente
Esto no es verdad 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 enviarlo.
fuente