Está creando los objetos que cree que necesitará en una primera prueba en TDD

15

Soy bastante nuevo en TDD y tengo problemas al crear mi primera prueba cuando aparece antes de cualquiera de los códigos de implementación. Sin ningún marco para el código de implementación, soy libre de escribir mi primera prueba como quiera, pero siempre parece salir manchada por mi forma de pensar Java / OO sobre el problema.

Por ejemplo, en mi Github ConwaysGameOfLifeExample la primera prueba que escribí (rule1_zeroNeighbours) Comencé creando un objeto GameOfLife que no tenía ' Se ha implementado todavía; se llamó un método de conjunto que no existía, un método de paso que no existía, un método de obtención que no existía y luego se usó un aserto.

Las pruebas evolucionaron a medida que escribía más pruebas y volví a redactarlas, pero originalmente parecía algo como esto:

@Test
public void rule1_zeroNeighbours()
{
    GameOfLife gameOfLife = new GameOfLife();
    gameOfLife.set(1, 1, true);
    gameOfLife.step();
    assertEquals(false, gameOfLife.get(1, 1));
}

Me sentí extraño porque estaba forzando el diseño de la implementación en función de cómo había decidido en esta etapa temprana escribir esta primera prueba.

De la forma en que entiendes TDD, ¿está bien? Parece que estoy siguiendo los principios de TDD / XP en el sentido de que mis pruebas e implementación evolucionaron a lo largo del tiempo con la refactorización, por lo que si este diseño inicial hubiera resultado inútil, habría estado abierto al cambio, pero parece que estoy forzando una dirección en el solución comenzando de esta manera.

¿De qué otra manera las personas usan TDD? Podría haber pasado por más iteraciones de refactorización al comenzar sin un objeto GameOfLife, solo primitivos y métodos estáticos, pero eso parece demasiado artificial.

    
pregunta Encaitar 17.03.2015 - 13:07
fuente

6 respuestas

9
  

Me sentí extraño porque estaba forzando el diseño de la implementación en función de cómo había decidido en esta etapa temprana escribir esta primera prueba.

Creo que este es el punto clave de su pregunta: si esto es deseable o no, depende de si se inclina hacia la idea de codeninja de que debe diseñar por adelantado y luego usar TDD para completar la implementación, o la idea de durron de que las pruebas deberían participar en la eliminación del diseño y la implementación.

Creo que cuál de estos prefieres (o dónde te encuentras en el medio) es algo que necesitas descubrir por ti mismo como una preferencia. Es útil entender los pros y los contras de cada enfoque. Probablemente hay muchos, pero yo diría que los principales son:

Pro Upfront Design

  • Por muy bueno que sea el proceso TDD en el diseño de conducción, no es perfecto. Tentar sin tener en mente un destino concreto a veces puede acabar en callejones sin salida, y al menos algunos de estos callejones sin salida podrían haberse evitado con un poco de reflexión inicial sobre dónde quiere terminar. Este artículo del blog presenta este argumento utilizando el ejemplo de los katas de números romanos, y tiene una implementación final bastante agradable para mostrar por ello.

Pro Test-Driving Design

  • Al construir su implementación alrededor de un cliente de su código (sus pruebas), obtiene el cumplimiento de YAGNI de forma gratuita, siempre y cuando no comience a escribir casos de prueba innecesarios. Más generalmente, obtienes una API diseñada para su uso por parte de un consumidor, que es en última instancia lo que deseas.

  • La idea de dibujar un montón de diagramas UML antes de escribir cualquier código y luego simplemente rellenar los huecos es agradable, pero rara vez es realista. En el Código completo de Steve McConnell, el diseño se describe como un "problema perverso", un problema que no se puede entender completamente sin primero resolverlo al menos parcialmente. Combine esto con el hecho de que el problema subyacente en sí mismo puede cambiar a través de requisitos cambiantes, y este modelo de diseño comienza a sentirse un poco desesperanzado. La prueba de manejo le permite solo tomar una porción del trabajo a la vez, en el diseño, no solo en la implementación, y saber que, al menos durante la vida útil de cambiar de rojo a verde, esa tarea todavía estará actualizada y será relevante.

En cuanto a su ejemplo particular, como dice durron, si optara por eliminar el diseño escribiendo la prueba más simple, consumiendo la interfaz mínima que puede, probablemente comenzaría con una interfaz más simple que la de su fragmento de código.

    
respondido por el Ben Aaronson 17.03.2015 - 15:17
fuente
17

Para escribir la prueba en primer lugar, debe diseñar la API que luego implementará. Ya ha comenzado con el pie equivocado al escribir su prueba para crear el objeto entero GameOfLife y usarlo para implementar su prueba.

De las Pruebas Unitarias Prácticas con JUnit y Mockito :

  

Al principio puede que te sientas incómodo por escribir algo que ni siquiera está allí. Requiere un ligero cambio en tus hábitos de codificación, pero después de un tiempo verás que es una gran oportunidad de diseño. Al escribir primero las pruebas, tiene la posibilidad de crear una API que sea conveniente para el uso de un cliente. Su prueba es el primer cliente de una API recién nacida. De esto se trata realmente TDD: el diseño de una API.

Su prueba no hace un gran intento de diseñar una API. Ha configurado un sistema con estado en el que toda la funcionalidad está contenida dentro de la clase GameOfLife externa.

Si tuviera que escribir esta aplicación, en lugar de eso, pensaría en las piezas que quiero construir. Por ejemplo, podría hacer una clase Cell , escribir pruebas para eso, antes de pasar a la aplicación más grande. Ciertamente, crearía una clase para la estructura de datos "infinito en todas las direcciones" que se requiere para implementar correctamente Conway, y probar eso. Una vez hecho todo eso, pensaría en escribir la clase general que tiene un método main y así sucesivamente.

Es fácil pasar por alto el paso "escribir una prueba que falla". Pero escribir la prueba de falla que funciona de la manera que usted quiere es el núcleo de TDD.

    
respondido por el durron597 17.03.2015 - 14:16
fuente
0

Hay diferentes escuelas de pensamiento sobre esto.

Algunos dicen: la prueba no está compilando es un error: corrige, escribe el código de producción más pequeño disponible.

Algunos dicen: está bien escribir primero en la prueba de verificación si apesta (o no) ant y luego crea clases / métodos faltantes

Con la primera aproximación estás realmente en un ciclo de refactor rojo-verde. En segundo lugar, tiene una visión general un poco más amplia de lo que quiere lograr.

Depende de usted elegir la forma de trabajar. En mi humilde opinión ambos enfoques son válidos.

    
respondido por el timoras 17.03.2015 - 13:33
fuente
0

Incluso cuando implemento algo en forma de "piratear juntos", todavía pienso en las clases y los pasos que estarán involucrados en todo el programa. Así que ya lo pensó y anotó estos pensamientos de diseño como una prueba primero. ¡Eso es genial!

Ahora siga iterando a través de ambas implementaciones para completar esta prueba inicial, y luego agregue más pruebas para mejorar y extender el diseño.

Lo que podría ayudarte es usar Pepino o similar para escribir tus pruebas.

    
respondido por el gbjbaanb 17.03.2015 - 14:08
fuente
0

Antes de comenzar a escribir sus pruebas, debe pensar en cómo diseñar su sistema. Debes pasar una cantidad considerable de tiempo durante tu fase de diseño. Si lo hiciste, no obtendrás esta confusión sobre TDD.

TDD es solo un enfoque de desarrollo link: TDD
1. Añadir una prueba
2. Ejecute todas las pruebas y vea si la nueva falla.
3. Escribe algún código
4. Ejecutar pruebas
5. Código refactor
6. Repita

TDD le ayuda a cubrir todas las funciones requeridas que ha planeado antes de comenzar a desarrollar su software. enlace: Beneficios

    
respondido por el codeninja.sj 17.03.2015 - 14:32
fuente
0

No me gustan las pruebas de nivel sistema escritas en java o C # por ese motivo. Mire a SpecFlow para c # o uno de los marcos de prueba basados en pepino para java (quizás JBehave). Entonces tus pruebas pueden verse más así.

Ypuedecambiareldiseñodesuobjetosintenerquecambiartodaslaspruebasdelsistema.

(laspruebasunitarias"normales" son excelentes cuando se prueban clases individuales.)

¿Cuáles son las diferencias entre los marcos BDD para Java?

    
respondido por el Ian 17.03.2015 - 18:00
fuente

Lea otras preguntas en las etiquetas