Pregunta

Mientras que he escrito las pruebas unitarias para la mayor parte del código que he hecho, lo único que hace poco llegó a mis manos una copia de TDD por ejemplo por Kent Beck. Siempre he lamentado ciertas decisiones de diseño que hice ya que han impedido la aplicación de ser 'verificable'. He leído a través del libro y mientras algunos de lo que parece extranjero, sentía que podía manejarlo y decidí probarlo en mi proyecto actual, que es básicamente un sistema cliente / servidor en el que las dos piezas se comunican a través. USB. Uno en el gadget y el otro en el host. La aplicación es en Python.

Me comenzó y muy pronto se enredó en un lío de reescrituras y pequeñas pruebas que más tarde que pensé que realmente no probar nada. Me tiró la mayoría de ellos y ahora tienen una aplicación de trabajo para los que las pruebas han coagulado en apenas 2.

Con base en mi experiencia, tengo un par de cuestiones que me gustaría preguntar. Gané información de Nuevo para TDD: ¿hay aplicaciones de ejemplo con pruebas para mostrar cómo hacer TDD pero tienen algunas preguntas específicas que me gustaría respuestas a / discusión sobre?.

  1. Kent Beck utiliza una lista que se suma a y golpea hacia fuera de guiar el proceso de desarrollo. ¿Cómo se hace una lista de este tipo? Yo inicialmente tenía algunos artículos como "servidor debe poner en marcha", "servidor debe abortar si el canal no está disponible", etc., pero se confundió y finalmente ahora, es sólo algo así como "cliente debe ser capaz de conectar con el servidor" (que subsumido el inicio del servidor, etc.).
  2. ¿Cómo se maneja vuelve a escribir? Yo inicialmente seleccionado un sistema dúplex medio basado en canalizaciones con nombre para que pudiera desarrollar la lógica de la aplicación en mi propia máquina y luego añadir la parte de comunicación USB. Se les trasladó a convertirse en una cosa basada zócalo y luego se trasladó el uso de los conectores directos a usar el módulo de Python SocketServer. Cada vez que las cosas cambiaron, me encontré con que tenía que volver a escribir partes considerables de las pruebas de lo que era molesto. Me había imaginado que las pruebas serían una guía algo invariable durante mi desarrollo. Se sentía como más código de manejar.
  3. necesitaba un cliente y un servidor para comunicarse a través del canal de probar cualquiera de los lados. Podía burlarse de uno de los lados para poner a prueba el otro, pero entonces todo el canal no sería puesta a prueba y me preocupa que me perdería eso. Esto perjudicó a todo el ritmo rojo / verde / refactor. Se trata sólo de la falta de experiencia o estoy haciendo algo mal?
  4. El "fingir hasta que lo consigas" me dejó con una gran cantidad de código desordenado que luego pasé un montón de tiempo para refactorizar y limpiar. Está presente como funcionan las cosas?
  5. Al final de la sesión, ahora tengo a mi cliente y el servidor que ejecuta con alrededor de 3 o 4 pruebas unitarias. Me tomó alrededor de una semana para hacerlo. Creo que podría haber hecho en un día si estuviera usando las pruebas de unidad después de manera código. No veo la ganancia.

Busco comentarios y consejos de personas que han puesto en marcha grandes proyectos que no son triviales completamente (o casi completamente) utilizando esta metodología. Tiene sentido para mí para seguir el camino después que tienen algo que ya está funcionando y desea agregar una nueva función, pero hacerlo desde cero parece tedioso y no vale la pena el esfuerzo.

P.S. :. Por favor, hágamelo saber si esto debe ser wiki de la comunidad y yo marcaré de esa manera

Actualizar 0 : Todas las respuestas fueron igualmente útiles. Elegí el que hice porque resonó con mis experiencias más.

Actualización 1 : Práctica Práctica Práctica

¿Fue útil?

Solución

Como observación preliminar, TDD requiere práctica. Cuando miro hacia atrás en las pruebas que escribí cuando empecé TDD, veo un montón de problemas, al igual que cuando miro código que escribí hace unos cuantos años. Sigue haciéndolo, y al igual que se empieza a reconocer un buen código de mal, lo mismo sucederá con sus pruebas - con paciencia.

  

¿Cómo se hace una lista de este tipo? yo   Inicialmente tenía algunos artículos como "servidor   debe poner en marcha "" servidor debe abortar   si el canal no está disponible", etc., pero   llegaron mixta y finalmente ahora, es   simplemente algo como "cliente debe ser   capaz de conectar con el servidor "

"La lista" puede ser bastante informal (que es el caso en el libro de Beck), pero cuando se mueve en la fabricación de los artículos en las pruebas, tratar de escribir las declaraciones en una "[Cuando algo le sucede a esta] y luego [esta afección deben ser verdad en ese formato]". Esto le obligará a pensar más en qué es lo que está verificando, cómo se verificarla y se traduce directamente en pruebas - o si lo hace, no debe darle una pista sobre qué pieza de funcionalidad no se encuentra. Piense en caso de uso / escenario. Por ejemplo, "servidor debe poner en marcha" no es clara, ya que nadie está iniciando una acción.

  

Cada vez que las cosas cambiaron, me encontré con que   Tenía que volver a escribir partes considerables de   las pruebas que era molesto. Carné de identidad   descubierto que las pruebas serían una   guía un tanto invariable durante mi   desarrollo. Se sentía como más   Código de manejar.

En primer lugar, sí, las pruebas son más código, y requiere un mantenimiento - y escribir pruebas mantenibles requiere práctica. Estoy de acuerdo con S. Lott, si necesita cambiar sus pruebas mucho, es probable que esté probando "muy profundo". Lo ideal sería que desea probar en el nivel de la interfaz pública, que no es probable que cambie, y no en el nivel del detalle de implementación, lo que podría evolucionar. Pero parte del ejercicio se trata de dar con un diseño, por lo que debe esperar para obtener algo de él mal y tienen que mover / refactorizar sus pruebas también.

  

Podría burlarse de uno de los lados para poner a prueba   el otro, pero entonces todo el canal   No se pondrá a prueba y me preocupa que   Que echaría de menos eso.

No del todo seguro de que uno. Desde el sonido de la misma, utilizando una maqueta era la idea correcta: tomar un lado, se burlan de la otra, y comprobar que funciona cada lado, suponiendo que el otro ha aplicado correctamente. Prueba de todo el sistema en conjunto es la prueba de integración, que también quiere hacer, pero no suele ser parte del proceso de TDD.

  

El "fingir hasta que lo consigas" me dejó   con una gran cantidad de código desordenado que más tarde   pasado mucho tiempo para refactorizar y   limpiar. Es este el funcionamiento de las cosas?

Debe pasar mucho tiempo mientras se hace refactorización TDD. Por otro lado, cuando es falso, es temporal, y su próximo paso debe ser inmediata a un-falso. Normalmente, usted no debería tener múltiples pruebas que pasan porque fingido -. Que debería concentrarse en una sola pieza a la vez, y trabajar en la refactorización lo antes posible

  

Creo que podría haber hecho en un día   si estuviera usando las pruebas de la unidad después de   forma de código. No veo la ganancia.

Una vez más, se necesita práctica, y usted debe llegar más rápido a través del tiempo. También, a veces TDD es más fructífero que los demás, me parece que en algunas situaciones, cuando sé exactamente el código que quiero escribir, es sólo más rápido para escribir una buena parte del código y, a continuación, escribir pruebas.
Además de Beck, un libro me gustó es el arte de las pruebas unitarias, por Roy Osherove. No es un libro TDD, y es Net-orientado, pero es posible que desee darle un aspecto de todos modos: una buena parte es acerca de cómo escribir pruebas mantenibles, la calidad pruebas y preguntas relacionadas. He encontrado que el libro resonó con mi experiencia después de tener pruebas escritas ya veces luchado para hacerlo bien ...
Así que mi consejo es, no tire el towel demasiado rápido, y darle un poco de tiempo. También puede ser que desee darle un tiro en algo más fácil - cosas comunicación del servidor de pruebas relacionadas no suena como el proyecto más fácil comenzar con

Otros consejos

  
      
  1. Kent Beck utiliza una lista ... por fin ahora, es sólo algo así como "cliente debe ser capaz de conectar con el servidor" (que subsumido servidor de arranque, etc.).
  2.   

A menudo, una mala práctica.

pruebas separadas para cada capa separada de la arquitectura son buenas.

pruebas consolidados tienden a oscurecer problemas de arquitectura.

Sin embargo, sólo probar las funciones públicas. No todas las funciones.

Y no invertir mucho tiempo en la optimización de su prueba. La redundancia en las pruebas no duele tanto como lo hace en la solicitud de trabajo. Si las cosas cambian y una prueba funciona, pero otra prueba de roturas, tal vez entonces se puede refactorizar sus pruebas. No antes.

  

2. ¿Cómo se maneja vuelve a escribir? ... Me di cuenta que tenía que volver a escribir partes considerables de las pruebas.

Se está probando en un nivel demasiado bajo de detalle. Probar la interfaz externa, pública y visible. La parte que se supone que es inmutable.

y

Sí, el cambio de arquitectura significativa significa un cambio significativo de la prueba.

y

El código de prueba es la forma de prueban las cosas funcionen. Es casi tan importante como la propia aplicación. Sí, es más código. Sí, debe manejarlo.

  

3. Necesitaba un cliente y un servidor para comunicarse a través del canal de probar cualquiera de los lados. Podía burlarse de uno de los lados para poner a prueba el otro, pero entonces todo el canal no sería puesta a prueba ...

Hay pruebas de unidad. Con burla.

Hay pruebas de integración, que ponen a prueba todo el asunto.

No los confunda.

Puede utilizar las herramientas de prueba de unidad para hacer las pruebas de integración, pero son cosas diferentes.

Y que tiene que hacer ambas cosas.

  

4. El "fingir hasta que lo hacen" me dejó con una gran cantidad de código desordenado que luego pasé un montón de tiempo para refactorizar y limpiar. Es este el funcionamiento de las cosas?

Sí. Eso es exactamente cómo funciona. A la larga, algunas personas encuentran esto más eficaz que devanan los sesos tratando de hacer todo el diseño en la delantera. Algunas personas no les gusta esto y quieren hacer todo el diseño en la delantera; usted es libre de hacer un montón de diseño por adelantado si quieres.

He encontrado que la refactorización es una buena cosa y diseño en la delantera es demasiado duro. Tal vez sea porque he estado de codificación para casi 40 años y mi cerebro se está desgastando.

  

5. No veo la ganancia.

Todos los verdaderos genios encuentran que las pruebas que se ralentiza.

El resto de nosotros no puede ser seguro nuestro código funciona hasta que tengamos un conjunto completo de pruebas que prueban que funciona.

Si usted no necesita prueba que el código funciona, usted no necesita pruebas.

  

Q. Kent Beck utiliza una lista que se suma a y golpea hacia fuera de guiar el proceso de desarrollo. ¿Cómo se hace una lista de este tipo? Yo inicialmente tenía algunos artículos como "servidor debe poner en marcha", "servidor debe abortar si el canal no está disponible", etc., pero se confundió y finalmente ahora, es sólo algo así como "cliente debe ser capaz de conectar con el servidor" (que subsumido el inicio del servidor, etc.).

Comienzo por recoger cualquier cosa que podría comprobar. En su ejemplo, que eligió "servidor se inicia".

Server starts

Ahora miro para cualquier prueba más simple puede ser que quiera escribir. Algo con menos variación, y un menor número de piezas móviles. Me podría considerar "servidor configurado correctamente", por ejemplo.

Configured server correctly
Server starts

Realmente, sin embargo, "servidor se inicia" depende de "servidor configurado correctamente", por lo que hacen que el vínculo claro.

Configured server correctly
Server starts if configured correctly

Ahora busco variaciones. Me pregunto: "¿Qué podría salir mal?" Podría configurar el servidor de forma incorrecta. ¿Cuántas maneras diferentes de que la materia? Cada uno de los que hace una prueba. ¿Cómo podría el servidor no se inicie a pesar de haberla configurado correctamente? Cada caso de que haga una prueba.

  

Q. ¿Cómo se maneja vuelve a escribir? Yo inicialmente seleccionado un sistema dúplex medio basado en canalizaciones con nombre para que pudiera desarrollar la lógica de la aplicación en mi propia máquina y luego añadir la parte de comunicación USB. Se les trasladó a convertirse en una cosa basada zócalo y luego se trasladó el uso de los conectores directos a usar el módulo de Python SocketServer. Cada vez que las cosas cambiaron, me encontré con que tenía que volver a escribir partes considerables de las pruebas de lo que era molesto. Me había imaginado que las pruebas serían una guía algo invariable durante mi desarrollo. Se sentía como más código de manejar.

Cuando cambio el comportamiento, creo que es razonable para cambiar las pruebas, e incluso cambiarlos primero! Si tengo que cambiar las pruebas que no se comprueban directamente en el comportamiento que estoy en el proceso de cambio, sin embargo, que es una señal de que mis pruebas dependen de muchos comportamientos diferentes. Esas son las pruebas de integración, que creo que son una estafa. (Google "pruebas de integración son una estafa")

  

Q. Necesitaba un cliente y un servidor para comunicarse a través del canal de probar cualquiera de los lados. Podía burlarse de uno de los lados para poner a prueba el otro, pero entonces todo el canal no sería puesta a prueba y me preocupa que me perdería eso. Esto perjudicó a todo el ritmo rojo / verde / refactor. Se trata sólo de la falta de experiencia o estoy haciendo algo mal?

Si construyo un cliente, un servidor y un canal, entonces trato de comprobar cada aisladamente. Comienzo con el cliente, y cuando una prueba de manejo que, decido cómo el servidor y el canal deben comportarse. Entonces implemento el canal y cada servidor para que coincida con el comportamiento que necesito. Al comprobar el cliente, me golpeo el canal; Al comprobar el servidor, me burlo del canal; Al comprobar el canal, me golpeo y se burlan de cliente y servidor. Espero que esto tenga sentido para usted, ya que tengo que hacer algunas suposiciones graves sobre la naturaleza de este cliente, el servidor y el canal.

  

Q. El "fingir hasta que lo hacen" me dejó con una gran cantidad de código desordenado que luego pasé un montón de tiempo para refactorizar y limpiar. Es este el funcionamiento de las cosas?

Si deja que su código de "fingir" en un auténtico lío antes de limpiarlo, entonces es posible que haya pasado demasiado tiempo fingiendo. Dicho esto, me parece que a pesar de que me acaban de limpiar más código con TDD, el ritmo general se siente mucho mejor. Esto viene de la práctica.

  

Q. Al final de la sesión, ahora tengo a mi cliente y el servidor que ejecuta con alrededor de 3 o 4 pruebas unitarias. Me tomó alrededor de una semana para hacerlo. Creo que podría haber hecho en un día si estuviera usando las pruebas de unidad después de manera código. No veo la ganancia.

Tengo que decir que a menos que el cliente y el servidor son muy, muy simple, que necesita más de 3 o 4 pruebas cada unopara comprobar a fondo. Voy a suponer que sus pruebas de verificación (o al menos ejecutar) una serie de comportamientos diferentes a la vez, y que podrían explicar el esfuerzo que se ha tomado en escribir ellos.

Además, no medir la curva de aprendizaje. Mi primera experiencia real de TDD consistía en volver a escribir el valor de trabajo de 3 meses de 9, 14 horas al día. Tenía 125 pruebas que se llevaron a 12 minutos para correr. No tenía idea de lo que estaba haciendo, y se sentía lento, pero se sentía constante, y los resultados fueron fantásticos. Me esencialmente re-escrito en 3 semanas lo que originalmente tomaron 3 meses a equivocarse. Si escribiera ahora, probablemente podría hacerlo en 3-5 días. ¿La diferencia? Mi banco de pruebas tendría 500 pruebas que se llevan a 1-2 segundos para funcionar. Que viene con la práctica.

Como programador novato, lo he encontrado difícil sobre desarrollo basado en pruebas fue la idea de que la prueba debe ser lo primero.

Para el principiante, eso no es realmente cierto. Diseño es lo primero. (interfaces, objetos y clases, métodos, lo que sea apropiado para su idioma.) A continuación, se escriben sus pruebas a eso. A continuación, se escribe el código que realmente hace cosas.

Ha sido un tiempo desde que miraba el libro, pero Beck parece escribir como si el diseño del código sólo una especie de inconsciente sucede en su cabeza. Para los programadores experimentados, eso puede ser cierto, pero para noobs como yo, Nuh-uh.

Me pareció que los primeros capítulos de código completo realmente útil para pensar en el diseño. Destacan el hecho de que su diseño puede también cambiar, incluso una vez que estás abajo en el nivel quid de la cuestión de la aplicación. Cuando esto sucede, es posible que también tenga que volver a escribir sus pruebas, porque se basaban en los mismos supuestos como su diseño.

La codificación es duro. Vamos de compras.

Las las canalizaciones con nombre se pusieron detrás de la interfaz de la derecha, cambiando la forma en que se implementa la interfaz (de canalizaciones con nombre para tomas a otra biblioteca enchufes) sólo deben pruebas de impacto para el componente que implementa la interfaz. Así que cortar las cosas más / diferente habría ayudado ... Eso interfaz de los zócalos están detrás probable que evolucione a.

empecé a hacer TDD tal vez hace 6 meses? Todavía estoy aprendiendo a mí mismo. Puedo decir con el tiempo mis pruebas y el código han mejorado mucho, por lo que mantenerlo. Realmente recomiendo el libro XUnit patrones de diseño también.

  

¿Cómo se hace una lista de este tipo para añadir a   y golpear a cabo a partir de guiar la   ¿proceso de desarrollo? Yo inicialmente tenía una   algunos artículos como "servidor debe comenzar   arriba "" servidor debe abortar si el canal   no está disponible"

Los productos en listas de tareas pendientes TDD son de grano más fino que eso, las pruebas apuntan a un comportamiento de un solo método, por ejemplo:

  • prueba con éxito la conexión del cliente
  • Prueba de conexión del cliente tipo de error 1
  • Prueba de conexión del cliente tipo de error 2
  • prueba con éxito la comunicación del cliente
  • falla la comunicación cliente de prueba cuando no están conectados

Se puede construir una lista de pruebas (positivos y negativos) para cada ejemplo que diste. Por otra parte, cuando la unidad de pruebas no se establece ninguna conexión entre el servidor y el cliente. Usted acaba de invocar métodos de aislamiento, ... Esto responde a la pregunta 3.

  

¿Cómo se maneja vuelve a escribir?

Si la unidad de pruebas de ensayo comportamiento y no la aplicación, entonces no tienen que ser reescrito. Si el código de prueba de unidad realmente crea una canalización con nombre para comunicarse con el código de producción y, entonces, evidentemente, las pruebas tienen que ser modificado cuando se cambia de tubería a la toma. Las pruebas unitarias se mantenga alejado de los recursos externos tales como sistemas de archivos, redes, bases de datos, ya que son lentos, pueden no estar disponibles ... ver estas normas de pruebas de unidad .

Esto implica la función de nivel más bajo no se prueban unidad, van a ser probadas con pruebas de integración, donde la totalidad del sistema se prueba de extremo a extremo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top