2010-08-08 12 views
20

Actualmente tengo como 10 pruebas que prueban cada vez que mi pieza Tetris no se mueve hacia la izquierda si hay una pieza en la ruta o una pared. Ahora, tendré que probar el mismo comportamiento para el movimiento correcto.¿Está bien copiar y pegar pruebas unitarias cuando la lógica es básicamente la misma?

¿Es una lástima si solo copio las 10 pruebas que ya tengo para el movimiento izquierdo y hago solo los cambios necesarios y hago lo mismo con el código mismo? ¿O debería volver y hacer cada prueba desde el principio, incluso si la lógica es básicamente la misma?

Respuesta

30

Intente tomar el tercer enfoque que no ha mencionado, el de refactorizar su código para que pueda compartir una implementación de la prueba entre las 10 pruebas.

Lo primero es que el código de duplicación casi siempre es lo incorrecto. En este ejemplo, podría refactorizar el código de comprobación en un método llamado, por ejemplo, IsTetrisPieceUnableToMoveLeftBecauseOfAPieceOrAWall. Siempre busco nombres de métodos muy descriptivos como ese cuando escribo un poco de funcionalidad "compartida" para una prueba unitaria, ya que deja muy claro lo que se está haciendo/probando.

+3

'Is_Tetris_piece_unable_to_move_left_because_of_a_piece_or_a_wall' – Inverse

+2

Gracias a Dios por la terminación automática. – mpen

+3

@Inverse, seguro, si los guiones bajos lo hacen por usted =) – Rob

14

El código de prueba es como cualquier otro código y debe mantenerse y refactorizarse.

Esto significa que si tiene una lógica compartida, extráigala a su propia función.

Algunas bibliotecas de pruebas unitarias, como la familia xUnit, tienen características específicas de prueba, configuración y atributos de desmontaje para dicho código compartido.

Ver pregunta relacionada con this - "¿Por qué es peligroso copiar y pegar el código?".

7

No hay nada de malo en copiar y pegar, y es un buen lugar para comenzar. De hecho, es mejor que desde cero, como si tuvieras código de trabajo (ya sea de prueba o no), luego copiar y pegar es más confiable que desde cero, y también más rápido.

Sin embargo, eso es solo el paso 1. El paso 2 es la refactorización de las características comunes, y el paso 1 es solo para ayudarlo a ver esa similitud. Si ya puede verlo claramente sin copiar (a veces es más fácil copiar primero y luego examinar, a veces no, y depende de la persona que lo está haciendo), omita el paso 1.

1

Si está repitiendo el código, entonces debes refactorizar. Su situación es un problema común y se resuelve con 'Prueba paramétrica'. La prueba paramétrica cuando es soportada por el arnés de prueba permite pasar múltiples conjuntos de valores de entrada como parámetros. También es posible que desee buscar las pruebas de Fuzz, he encontrado que es útil en situaciones como esta.

+0

¿Cómo es útil la prueba de fuzz en el ejemplo? – Dave

22

Tengo una posición un tanto controvertida en este caso. Mientras que la duplicación de código debe evitarse tanto como sea posible en el código de producción, esto no es tan malo para el código de prueba. Producción y prueba de código difieren en la naturaleza y la intención:

  • Código de producción puede permitirse cierta complejidad a fin de ser comprensible/mantenible. Desea que el código esté en el nivel de abstracción correcto y que el diseño sea coherente. Esto está bien porque tienes pruebas para eso y puedes asegurarte de que funcione. La duplicación de código en el código de producción no sería un problema si realmente tuvieras una cobertura de código del 100% en el nivel lógico. Esto es realmente difícil de lograr, por lo que la regla es: evitar la duplicación y maximizar la cobertura del código.

  • El código de prueba, por otro lado, debe ser lo más simple posible. Debe asegurarse de que el código de prueba en realidad prueba lo que debería. Si las pruebas son complicadas, puede terminar con errores en las pruebas o en las pruebas incorrectas, y no tiene pruebas para las pruebas, por lo que la regla es: mantenerlo simple. Si el código de prueba está duplicado, este no es un gran problema cuando algo cambia. Si el cambio se aplica solo en una prueba, la otra fallará hasta que la solucione.

El punto principal que quiero hacer es que la producción y el código de prueba tienen una naturaleza diferente. Entonces siempre es una cuestión de sentido común, y no estoy diciendo que no debas factorizar el código de prueba, etc. Si puedes factorizar algo en el código de prueba y estás seguro de que está bien, entonces hazlo. Pero para el código de prueba, preferiría la simplicidad a la elegancia, mientras que para el código de producción, preferiría la elegancia a la simplicidad. Lo óptimo es, por supuesto, tener una solución simple y elegante :)

PD: Si realmente no está de acuerdo, por favor deje un comentario.

+1

+1, creo que tu argumento es convincente. Quizás podríamos decir si nuestro código tiene una complejidad de nivel x, entonces debe ser probado. Esto se aplica al código de prueba también. Entonces, si una refactorización adecuada aumenta la complejidad del código de prueba por encima de x, entonces (1) refactorizar y agregar otro nivel de prueba; o (2) Keep It Simple Stupid. – emory

+0

Estoy de acuerdo con su punto de que el código de prueba debe ser simple.Pero, al mismo tiempo, debe ser mantenible y duplicar el código no es lo que le gustaría hacer –

+2

@ P.K En realidad, el código con duplicación es la mayoría de las veces más fácil de entender, porque su complejidad es baja (menos abstracción). Entonces el mantenimiento no es difícil, pero podría ser un poco repetitivo. En la ingeniería de software, la mayor parte del tiempo es * entender * lo que se debe hacer, no * hacerlo *. Si mantener las pruebas es repetitivo y aburrido, está bien, así debería ser. El problema con la duplicación es el miedo a no actualizar la lógica en todos los lugares. No puede correr el riesgo de que el código de producción deje de notarse una incoherencia, pero en el código de prueba, la prueba fallará hasta que la modifique. – ewernli

1

Recuerde que sus pruebas están presionando contra su código. Si encuentra que sus pruebas se ven duplicadas, excepto por algo como izquierda/derecha, entonces tal vez exista un código subyacente que a la derecha y a la izquierda se esté duplicando. Por lo tanto, es posible que desee ver si puede refactorizar su código para usarlo a la izquierda o a la derecha y enviarle una bandera izquierda o derecha.

+0

No estoy seguro, como yo lo veo, la estructura del código de prueba no depende de la estructura del código probado. Por ejemplo, puedo usar el mismo código de prueba para probar muchas implementaciones diferentes de un Servidor HTTP – Dave

+0

La idea detrás de eliminar la duplicación en su prueba es que puede ayudarlo a crear una interfaz más abstracta en su SUT. Esto te ayudará a refinar los objetos que estás probando. Además, recuerde que cuanta más duplicación tenga en sus pruebas, mayor será la carga de mantenimiento o mayor será su deuda técnica. – Gutzofter

1

El sitio web xunitpatterns.org dice "no" (copiar/pegar no está bien), ya que puede aumentar los costos cuando las pruebas deben ser actualizados:

" Cortar y pegar "es una herramienta poderosa para escribir código rápidamente, pero da como resultado muchas copias del mismo código, cada una de las cuales debe ser mantenida en paralelo.

y para la lectura adicional que también se vincula al artículo

por Arie van Deursen, León Moonen, Alex van den Bergh, Gerard Kok

1

I acuerdo @Rob. El código necesita refactorización. Pero si no desea refactorizar el código en este punto de tiempo, entonces puede ir y tener pruebas parametrizadas. La misma prueba se ejecuta para diferentes parámetros. Ver los atributos TestCase y TestCaseSource en nunit.

Consulte http://nunit.org/index.php?p=parameterizedTests&r=2.5

Cuestiones relacionadas