Código de prueba copiado y pegado: ¿qué tan malo es esto?

12

Mi trabajo actual es principalmente escribir código de prueba GUI para varias aplicaciones en las que trabajamos. Sin embargo, encuentro que tiendo a copiar y pegar mucho código dentro de las pruebas. La razón de esto es que las áreas que estoy probando tienden a ser lo suficientemente similares como para necesitar repetición, pero no lo suficientemente similares como para encapsular código en métodos u objetos. Encuentro que cuando trato de usar clases o métodos de manera más extensa, las pruebas se vuelven más engorrosas de mantener y, a veces, absolutamente difíciles de escribir en primer lugar.

En cambio, generalmente copio una gran porción de código de prueba de una sección y la pego en otra, y hago los cambios menores que necesito. No uso formas más estructuradas de codificación, como el uso de más principios o funciones OO.

¿Otros codificadores se sienten así al escribir el código de prueba? Obviamente quiero seguir los principios DRY y YAGNI, pero encuentro que el código de prueba (código de prueba automatizado para pruebas GUI de todos modos) puede hacer que estos principios sean difíciles de seguir. ¿O solo necesito más práctica de codificación y un mejor sistema general de hacer las cosas?

EDITAR: La herramienta que estoy usando es SilkTest, que está en un lenguaje propietario llamado 4Test. Además, estas pruebas son principalmente para aplicaciones de escritorio de Windows, pero también he probado aplicaciones web con esta configuración.

joshin4colours
fuente
¿Qué herramienta de prueba estás usando? Puede ser que su marco de pruebas no sea compatible con los tipos de pruebas que está escribiendo. Cortar y pegar de más de 3 líneas generalmente es realmente malo, pero si puede agregar claramente más valor a largo plazo al automatizar una prueba de GUI que al realizarla manualmente cada vez, entonces lo que sea que esté haciendo probablemente sea bastante maldito bueno.
GlenPeterson
Además, ¿qué idioma es este? Es posible que tenga algo disponible que simplemente no se le ocurra, que permita la reutilización (como funciones de primera clase). Por otro lado, se supone que los casos de prueba deben ser simples, para que sea menos probable que tengan errores ellos mismos ...
Izkata
3
En todo lo que he escrito, el código de prueba no está excluido de la refactorización ..
Simon Whitehead

Respuestas:

23

Los casos de prueba copiados y luego editados a menudo están bien.

Las pruebas deben tener la menor cantidad de dependencias externas posible y ser lo más sencillo posible. Los casos de prueba tienden a cambiar con el tiempo, y anteriormente los casos de prueba casi idénticos pueden divergir repentinamente. Actualizar un caso de prueba sin tener que preocuparse por romper otros casos es una buena cosa.

Por supuesto, el código repetitivo que es idéntico en muchos casos de prueba y tiene que cambiar en concierto puede y debe ser eliminado.

9000
fuente
1
Así es principalmente como me siento. El código de prueba casi idéntico está bien en muchos casos, pero el código de prueba idéntico repetido es una mala noticia.
joshin4colours
12

La repetición es la raíz de todo mal

¡Eso es correcto! La repetición es la raíz de todo mal . Probablemente fue Knuth diciendo en su libro "La optimización prematura es la raíz de todo mal", pero creo que es la repetición.

Cada vez que miras un programa o estás escribiendo uno y descubres algún tipo de repetición: ¡elimínalo! Mátalo inmediatamente ... ¡lo que sea, pero deshazte de él !

Cada vez que introduje algún tipo de repetición y tuve que arreglar un error allí, olvidé arreglar la réplica ... (Donald Knuth) Entonces, cada vez que haya una repetición, elimínela lo mejor que pueda, no piratee !

Piense en un diseño limpio y esbelto (como encapsular sus bloques de código repetidos en clases auxiliares) y escriba algunas pruebas antes de cambiar algo (solo para asegurarse de no romper algo). Esto es cierto para cualquier código escrito y los códigos de prueba no son una excepción.

Aquí hay una buena lectura de Code Horror que me inspira: una modesta propuesta para copiar y pegar la escuela de reutilización de código .

Yusubov
fuente
"Cada vez que introduje algún tipo de repetición y tuve que arreglar un error allí, olvidé arreglar la réplica ..." exactamente. Además, si hace c & p y olvida ajustar el texto copiado a su contexto actual, esto le dolerá mucho. El código de prueba con errores no suena como la situación óptima, ¿verdad?
marktani
sí, tomé las estaciones de Knuth :)
Yusubov
99
Se repitió: repitió diciendo "La repetición es la raíz de todo mal" en el título y en la oración de introducción.
Thomas Eding
Sí, lo hice intencionalmente para enfatizar la importancia y puedes editar
esa
1
Thomas Eding, te repitiste a ti mismo también. También te
repitiste
7

Todavía es bastante malo cortar y pegar. Hay algunos problemas

Es posible que sus pruebas sean frágiles, porque es vulnerable a algo que requiere un cambio en todo ese código copiado y pegado. ¿Tendrás que reescribir todas las pruebas?

Si no puede encapsular la lógica en métodos auxiliares fuera de sus pruebas, no puede escribir pruebas de esos métodos auxiliares. Escribir pruebas de métodos de prueba suele ser demasiado difícil de hacer, ya que debe romper su código para probar la prueba. Pero puede probar métodos auxiliares de prueba.

Bien puede hacer que las pruebas sean menos legibles. Un gran bloque de código copiado puede ser más difícil de leer que una llamada al método auxiliar con un nombre descriptivo.

Todo lo que he enumerado es algo que puede ser un problema. Si encuentra que ninguno de ellos en realidad son un problema, entonces por supuesto que está bien.

psr
fuente
> una llamada al método auxiliar con un nombre descriptivo. ¿No es el problema con esto que las pruebas unitarias ahora se están convirtiendo en programas en sí mismas? ¿Qué sucede si algunas pruebas fallan, es el código que está roto o los ayudantes de prueba?
dwjohnston
4

Solía ​​estar de acuerdo contigo. Pero luego, con el tiempo, descubrí que cada cambio que hacía (particularmente los cambios DI en las pruebas unitarias) requería numerosas pruebas para cambiar y eso era engorroso. Ahora me suscribo a la escuela de DRY, incluso cuando escribo exámenes.

Para las pruebas de GUI, es posible que desee mirar el patrón de PageObject para reducir el código repetido.

pdr
fuente
2

Recomendaría elegir patrones XUnit. Solía ​​tener exactamente el mismo problema hasta que comencé a aprovechar ese libro. El patrón Madre de objeto suena como si fuera el más útil para su escenario.

Como alguien más mencionó, encapsular adecuadamente este código de configuración puede ser oneroso, pero tener que cambiarlo en todos los lugares que copia y pega es aún más.

Michael Brown
fuente
+1 para el Object Mother patterncódigo de inicialización común.
k3b
2

Si las personas intentan limitar la repetición cuando pueden, sí. Pero la recompensa depende de la situación. Esto podría volver al debate sobre las "mejores prácticas". Pero la pregunta es qué es lo mejor para usted en esta situación. Hay excepciones a cada regla.

Un par de cosas que pediría son: 1) ¿Qué posibilidades hay de que cambie esta funcionalidad que se está probando en la UAT? Si es poco probable que cambie, entonces hay menos posibilidades de que tenga que actualizar cada uno de sus conjuntos de código. 2) Si hay un cambio en UAT, ¿afectará siempre a cada conjunto del código copiado o podría afectar solo uno o dos conjuntos? Si puede estar aislado y solo requiere un cambio en un conjunto, puede ser útil separar las cosas. 3) ¿Qué tan complejo será el método inicial si intenta que maneje todos los escenarios? ¿Está agregando muchos bucles anidados if / else / loops? Si comienza a hacer todas las ramificaciones, puede terminar con un código que es difícil de comprender. ¿Sería más fácil realizar la actualización en cada texto copiado que volver a visitar toda la lógica de ramificación?

Si está atascado, copie / pegue / altere, creo que desea agregar comentarios como 'Esto se copia en el método xyz'. De esa forma, se le recordará que actualice todas las versiones pegadas del código. O (viniendo de otro usuario de SilkTest) podría agregar un archivo inc separado que se centraría solo en este código repetido. De esa manera, tiene todas las variaciones en un solo lugar y puede ver fácilmente los diferentes métodos que requerirían una actualización.

Dan B
fuente
0

Un gran procedimiento

Un pensamiento: Parece que está tratando de evitar el código de cortar y pegar haciendo métodos como:

testScreen(title, fieldList, linkList, param1, param2, param3,...) {
    test that the layout at the top of the screen is correct
    test if PageTitle == title?
    for each field in fieldList:
        check that it appears in order on the screen
    for each field in linkList:
        check that it appears in order on the screen
    test if param1 is whatever...
    test if param2 is whatever...
    etc.
    test that the bottom of the screen is correct
}

Muchos pequeños procedimientos (kit de herramientas)

¿También has considerado el enfoque opuesto? En lugar de pasar un millón de parámetros a un gran procedimiento testScreen (), tal vez cree su propio marco o kit de herramientas de pequeños procedimientos auxiliares que usted pueda preparar cuando los necesite. Me gusta:

testScreenTop()
verifyLinks(list)
testScreenBottom()

Aún puede cortar y pegar estos procedimientos en cada pantalla, pero está cortando y pegando fragmentos de código más pequeños y creando fragmentos de elementos comunes que no se cortan y pegan (el contenido de cada pequeño procedimiento).

Cortar y pegar

El único momento en que el código cortado y pegado no me ha mordido fue cuando el código fue desechado antes de que tuviera que cambiarlo. Mi mayor preocupación con las pruebas de IU es qué tan rápido se vuelven obsoletas. Si descubre que tira todo su código antes de cambiarlo, entonces tal vez haya encontrado un nicho donde cortar y pegar está bien. Además, no es tan malo cuando no hay código aguas abajo del código cortado y pegado (por ejemplo, en la interfaz de usuario de una aplicación). Si está pegando más de 3 líneas, realmente consideraría hacer algo al respecto. ¡Al menos tome medidas para minimizarlo!

Prueba automatizada de IU

Demonios, si puede demostrar una mayor productividad con las pruebas de IU automatizadas que las pruebas manuales con cualquier técnica (el costo de escribir / mantener pruebas automatizadas es menor que las pruebas manuales cada vez, pero la calidad es la misma) Creo que debería escribir un documento. ¡Lo leería! Ahora puedo ver el título, "¡Cortar y pegar, codifique una ganancia neta para las pruebas de IU!"

GlenPeterson
fuente
0

En realidad no está tan mal. De hecho, si encuentra que ciertos patrones de código se usan con mucha frecuencia y los cambios son muy rutinarios (como algunas cadenas o valores de parámetros), incluso podría escribir un generador de código que genere código de prueba repetitivo basado en un pequeño (- ish?) lista de entrada de valores que cambian. He hecho esto (código de prueba generado) muchas veces, usando archivos por lotes, scripts de SQLPlus, incluso macros de Excel (suena feo, pero las variables para los diferentes scripts de prueba ya estaban en una hoja de cálculo) y puede ser un gran ahorro de tiempo . La cuestión es que si algo cambia en la estructura general del código de caso de prueba repetitivo, puede regenerar lo que necesite.

FrustratedWithFormsDesigner
fuente
0

Esto es lo mismo que la mayoría de las otras respuestas, pero de una manera que un gerente no técnico puede entender.

Imagine el siguiente escenario de error:

  • Alguien realiza cambios en la tabla de la base de datos de la que dependen muchas de sus pruebas.
  • Consecuencia: de repente 117 de sus 2933 pruebas automatizadas fallan.

¿Qué harás?

  • (1) arregla 117 pruebas?
  • (2) elimine las 117 pruebas y vuelva a implementarlas mediante una nueva copia y pegue. esto podría ser más fácil que (1)
  • (3) refactorice las pruebas para extraer el código común para que en el futuro tenga que adaptar solo un método (o algunos) para arreglar las pruebas (vea las respuestas de @pdr o @Michael Brown)
  • (4) elimine las 117 pruebas sin volver a implementar las pruebas

De acuerdo con mi experiencia:

Al introducir pruebas automatizadas de gestión como "copiar y pegar pruebas": obtiene muchas pruebas en poco tiempo.

Después de algunos de los "escenarios de error", la administración prefiere (4) porque arreglar "copiar y pegar pruebas" es muy costoso.

Hacerlo bien en primer lugar (3) no será tan rápido pero aumenta las posibilidades de que las pruebas sobrevivan

k3b
fuente