¿Cuándo escribes el código "real" en TDD?

johnny 08/19/2017. 11 answers, 20.464 views
tdd

Todos los ejemplos que he leído y visto en videos de entrenamiento tienen ejemplos simplistas. Pero lo que no veo es cómo hago el código "real" después de que me pongo verde. ¿Es esta la parte del "Refactor"?

Si tengo un objeto bastante complejo con un método complejo, y escribo mi prueba y el mínimo indispensable para que pase (después de que falla primero, Rojo). ¿Cuándo vuelvo y escribo el código real? ¿Y cuánto código real escribo antes de volver a probar? Supongo que el último es más intuición.

Edit: Gracias a todos los que respondieron. Todas sus respuestas me ayudaron inmensamente. Parece haber diferentes ideas sobre lo que estaba preguntando o sobre lo que estaba confundido, y tal vez sí, pero lo que estaba preguntando era, digamos, que tengo una aplicación para construir una escuela.

En mi diseño, tengo una arquitectura con la que quiero empezar, User Stories, etc. A partir de aquí, tomo esas historias de usuario y creo una prueba para probar la historia de usuario. El usuario dice: Tenemos personas que se inscriben en la escuela y pagan las tarifas de registro. Entonces, pienso en una manera de hacer que eso falle. Al hacerlo, diseño una Clase de prueba para la clase X (tal vez Estudiante), que fallará. Luego creo la clase "Estudiante". Tal vez "escuela" no lo sé.

Pero, en cualquier caso, el TD Design me obliga a pensar en la historia. Si puedo hacer que una prueba falle, sé por qué falla, pero esto presupone que puedo hacer que pase. Se trata del diseño.

Yo lo comparo con pensar en la Recursividad. La recursividad no es un concepto difícil. Puede ser más difícil hacer un seguimiento de ello en tu cabeza, pero en realidad, la parte más difícil es saber, cuando la recursión "se rompe", cuándo parar (mi opinión, por supuesto). Así que tengo que pensar en qué se detiene la Recursión primero. Es solo una analogía imperfecta, y supone que cada iteración recursiva es un "pase". De nuevo, solo una opinión.

En implementación, la escuela es más difícil de ver. Los libros contables numéricos y bancarios son "fáciles" en el sentido de que puede usar aritmética simple. Puedo ver a + b y devolver 0, etc. En el caso de un sistema de personas, tengo que pensar más en cómo implement . Tengo el concepto de fail, pass, refactor (sobre todo por el estudio y esta pregunta).

Lo que no sé se basa en la falta de experiencia, en mi opinión. No sé cómo dejar de registrar a un nuevo estudiante. No sé cómo fallar a alguien escribiendo un apellido y guardándolo en una base de datos. Sé cómo hacer un +1 para matemática simple, pero con entidades como una persona, no sé si solo estoy probando para ver si obtengo una ID única de la base de datos u otra cosa cuando alguien ingresa un nombre en una base de datos o ambos o ninguno.

O, tal vez esto muestra que todavía estoy confundido.

5 Comments
187 hobbs 07/25/2017
Después de la TDD, la gente se va a casa a pasar la noche.
14 Goyo 07/25/2017
¿Por qué crees que el código que escribiste no es real?
2 johnny 07/26/2017
@RubberDuck Más que las otras respuestas. Estoy seguro de que me referiré a él pronto. Todavía es un poco extraño, pero no voy a renunciar a él. Lo que dijiste tenía sentido. Solo trato de hacer que tenga sentido en mi contexto o en una aplicación comercial habitual. Tal vez un sistema de inventario o similar. Tengo que considerarlo. Aunque estoy agradecido por tu tiempo. Gracias.
1 Edmund Reed 07/26/2017
Las respuestas ya han dado en el clavo, pero mientras pasen todas las pruebas y no necesites ninguna prueba / funcionalidad nueva, se puede suponer que el código que tienes ha finalizado.
3 Borjab 07/26/2017
Hay una asunción en la pregunta que puede ser problemática en "Tengo un objeto bastante complejo con un método complejo". En TDD, primero escribe sus pruebas para que comience con un código bastante simple. Esto te obligará a codificar una estructura amigable para las pruebas que deberá ser modular. Entonces se creará un comportamiento complejo al combinar objetos más simples. Si finalizas con un objeto o método bastante complejo, entonces es cuando refactorizas

11 Answers


RubberDuck 07/27/2017.

Si tengo un objeto bastante complejo con un método complejo, y escribo mi prueba y el mínimo indispensable para que pase (después de que falla primero, Rojo). ¿Cuándo vuelvo y escribo el código real? ¿Y cuánto código real escribo antes de volver a probar? Supongo que el último es más intuición.

No "retrocedes" y escribes "código real". Es todo código real. Lo que debes hacer es volver atrás y agregar otra prueba que te forces a change tu código para que pase la nueva prueba.

¿En cuanto a la cantidad de código que escribes antes de volver a probar? Ninguna. Escribe zero código sin una prueba de falla que lo forces a escribir más código.

Observe el patrón?

Veamos otro ejemplo simple con la esperanza de que ayude.

 Assert.Equal("1", FizzBuzz(1)); 

Fácil de pelar.

 public String FizzBuzz(int n) {
    return 1.ToString();
} 

No es lo que llamarías código real, ¿verdad? Agreguemos una prueba que fuerza un cambio.

 Assert.Equal("2", FizzBuzz(2)); 

Podríamos hacer algo tonto como if n == 1 , pero saltaremos a la solución sensata.

 public String FizzBuzz(int n) {
    return n.ToString();
} 

Guay. Esto funcionará para todos los números que no sean de FizzBuzz. ¿Cuál es la siguiente entrada que obligará al código de producción a cambiar?

 Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
} 

Y otra vez. Escribe una prueba que no pasará aún.

 Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
} 

Y ahora hemos cubierto todos los múltiplos de tres (que no son también múltiplos de cinco, lo notaremos y volveremos).

Todavía no hemos escrito una prueba para "Buzz", así que vamos a escribir eso.

 Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
} 

Y nuevamente, sabemos que hay otro caso que debemos manejar.

 Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
} 

Y ahora podemos manejar todos los múltiplos de 5 que no sean múltiplos de 3.

Hasta este momento, hemos estado ignorando el paso de refactorización, pero veo cierta duplicación. Vamos a limpiar eso ahora.

 private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Guay. Ahora eliminamos la duplicación y creamos una función bien nombrada. ¿Cuál es la próxima prueba que podemos escribir que nos obligará a cambiar el código? Bueno, hemos estado evitando el caso donde el número es divisible por 3 y 5. Vamos a escribirlo ahora.

 Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Las pruebas pasan, pero tenemos más duplicación. Tenemos opciones, pero voy a aplicar "Extraer variable local" varias veces para que podamos refactorizar en lugar de volver a escribir.

 public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Y hemos cubierto todas las aportaciones razonables, pero ¿qué pasa con la entrada unreasonable ? ¿Qué pasa si pasamos 0 o un negativo? Escribe esos casos de prueba.

 public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

¿Esto empieza a parecerse al "código real" todavía? Más importante aún, ¿en qué punto dejó de ser un "código irreal" y la transición a ser "real"? Eso es algo en que reflexionar ...

Entonces, pude hacer esto simplemente buscando una prueba que sabía que no pasaría en cada paso, pero he tenido mucha práctica. Cuando estoy en el trabajo, las cosas nunca son tan simples y no siempre sé qué prueba forzará un cambio. ¡A veces escribiré una prueba y me sorprendería ver que ya pasó! Le recomiendo que adquiera el hábito de crear una "Lista de prueba" antes de comenzar. Esta lista de prueba debe contener todas las entradas "interesantes" que se te ocurran. Puede que no los use todos y probablemente agregue casos a medida que avanza, pero esta lista sirve como una hoja de ruta. Mi lista de pruebas para FizzBuzz se vería así.

  • Negativo
  • Cero
  • Uno
  • Dos
  • Tres
  • Las cuatro
  • Cinco
  • Seis (múltiplo no trivial de 3)
  • Nueve (3 cuadrados)
  • Diez (múltiplo no trivial de 5)
  • 15 (múltiplo de 3 y 5)
  • 30 (múltiplo no trivial de 3 y 5)
5 comments
3 maple_shaft♦ 07/27/2017
Los comentarios no son para una discusión extensa; esta conversación se movió al chat .
40 GManNickG 07/27/2017
A menos que malinterprete por completo esta respuesta: "Podríamos hacer algo tonto como si n == 1, pero saltaremos a la solución sensata". - Todo fue una tontería. Si sabe de antemano que quiere una función que tenga <especificación>, escriba pruebas para <especificación> y omita la parte en la que escribe versiones que obviamente fallan <especificación>. Si encuentra un error en <spec>, entonces seguro: primero escriba una prueba para verificar que puede ejercitarla antes de la corrección y observe que la prueba pasa después de la corrección. Pero no hay necesidad de falsificar todos estos pasos intermedios.
15 user3791372 07/28/2017
Los comentarios que señalan los principales defectos en esta respuesta y TDD en general se han movido al chat. Si está considerando usar TDD, lea el 'chat'. Lamentablemente, los comentarios de 'calidad' ahora están ocultos entre una carga de chat para que los futuros estudiantes puedan leer.
nbro 07/28/2017
Sería más preciso con respecto al contenido de esta "lista de prueba", si desea mejorar esta respuesta. Hablaría explícitamente sobre "valores límite" y "partición de clase".
2 hvd 07/30/2017
@GManNickG Creo que el punto es obtener la cantidad correcta de pruebas. Escribir las pruebas de antemano hace que sea fácil pasar por alto los casos especiales que deben probarse, lo que lleva a situaciones que no se cubren adecuadamente en las pruebas, o a la misma situación que se cubre inútilmente muchas veces en las pruebas. Si puedes hacer eso sin estos pasos intermedios, ¡genial! Sin embargo, no todos pueden hacerlo, es algo que requiere práctica.

GenericJon 07/24/2017.

El código "real" es el código que usted escribe para hacer su pase de prueba. Really Es así de simple.

Cuando las personas hablan de escribir lo mínimo para hacer que la prueba sea verde, eso significa que su código real debe seguir el principio de YAGNI .

La idea del paso de refactorización es simplemente limpiar lo que ha escrito una vez que esté satisfecho de que cumpla con los requisitos.

Siempre que las pruebas que escriba realmente abarquen los requisitos de su producto, una vez que estén aprobando, el código estará completo. Piénselo, si todos los requisitos de su negocio tienen una prueba y todas esas pruebas son verdes, ¿qué más hay para escribir? (De acuerdo, en la vida real no tendemos a tener una cobertura de prueba completa, pero la teoría es sólida).

5 comments
44 Derek Elkins 07/24/2017
Las pruebas unitarias en realidad no pueden abarcar los requisitos de su producto incluso para requisitos relativamente triviales. En el mejor de los casos, toman muestras del espacio de entrada-salida y la idea es que usted (correctamente) generalice al espacio completo de entrada-salida. Por supuesto, su código podría ser un gran switch con un caso para cada prueba unitaria que pasaría todas las pruebas y fallaría para cualquier otra entrada.
8 Taemyr 07/25/2017
@DerekElkins TDD exige pruebas deficientes. No fallar pruebas unitarias.
6 jonrsharpe 07/25/2017
@DerekElkins es por eso que no solo escribes pruebas unitarias, y también por qué hay una suposición general de que estás tratando de hacer algo, ¡no solo de fingirlo!
35 Derek Elkins 07/25/2017
@jonrsharpe Por esa lógica, nunca escribiría implementaciones triviales. Por ejemplo, en el ejemplo de FizzBuzz en la respuesta de RubberDuck (que solo usa pruebas unitarias), la primera implementación claramente "simplemente lo falsifica". Mi comprensión de la pregunta es exactamente esta dicotomía entre escribir código que sabes que está incompleto y código que realmente crees que implementará el requisito, el "código real". Mi "gran switch " fue pensado como un extremo lógico de "escribir el mínimo indispensable para hacer que las pruebas sean verdes". Veo la pregunta del OP como: ¿dónde en TDD está el principio que evita este gran switch ?
2 Luaan 07/25/2017
@GenericJon Eso es un poco demasiado optimista en mi experiencia :) Por un lado, hay personas que disfrutan del trabajo repetitivo sin sentido. Estarán más felices con una declaración de cambio gigante que con una "toma de decisiones complicada". Y para perder su trabajo, necesitarían a alguien que los llamara sobre la técnica (¡y es mejor que tengan buena evidencia de que en realidad está perdiendo las oportunidades de la compañía / dinero!), O lo harán excepcionalmente mal. Después de asumir el mantenimiento de muchos de esos proyectos, puedo decir que es fácil que un código muy ingenuo dure décadas, siempre y cuando el cliente esté contento (y pague).

Carl Raymond 07/24/2017.

La respuesta corta es que el "código real" es el código que hace pasar la prueba. Si puede hacer que su prueba pase con algo diferente al código real, ¡agregue más pruebas!

Estoy de acuerdo en que muchos tutoriales sobre TDD son simplistas. Eso funciona en contra de ellos. Una prueba demasiado simple para un método que, digamos, calcula 3 + 8 realmente no tiene otra opción que calcular 3 + 8 y comparar el resultado. Eso hace que parezca que solo va a duplicar el código, y que las pruebas son inútiles, propensas a errores.

Cuando eres bueno en las pruebas, eso te informará cómo estructuras tu aplicación y cómo escribes tu código. Si tiene problemas para encontrar pruebas sensatas y útiles, probablemente debería reconsiderar su diseño un poco. Un sistema bien diseñado es fácil de probar, lo que significa que las pruebas sensibles son fáciles de pensar y de implementar.

Cuando primero escribes tus pruebas, ves que fallan y luego escribes el código que las hace aprobar, esa es una disciplina para garantizar que todo tu código tenga las pruebas correspondientes. No sigilosamente sigo esa regla cuando estoy codificando; a menudo escribo pruebas después del hecho. Pero hacer las pruebas primero te ayuda a ser honesto. Con algo de experiencia, empezarás a darte cuenta cuando estés codificando en una esquina, incluso cuando no estés escribiendo pruebas primero.

4 comments
6 Steve Jessop 07/26/2017
Personalmente, la prueba que escribiría sería assertEqual(plus(3,8), 11) , no assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)) . Para casos más complejos, siempre busca un medio para probar el resultado correcto, other than calcular dinámicamente el resultado correcto en la prueba y verificar la igualdad.
Steve Jessop 07/26/2017
Entonces, para una manera realmente tonta de hacerlo en este ejemplo, puedes probar que el plus(3,8) ha devuelto el resultado correcto restando 3 de él, restando 8 de eso, y comprobando el resultado contra 0. Esto es tan obvio equivalente a assertEqual(plus(3,8), 3+8) para ser un poco absurdo, pero si el código bajo prueba construye algo más complicado que solo un entero, entonces tomar el resultado y verificar que cada parte sea correcta es a menudo el enfoque correcto. Alternativamente, algo así como for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop 07/26/2017
... ya que eso evita el gran temor, que al escribir la prueba cometeremos el mismo error sobre el tema "cómo agregar 10" que hicimos en el código en vivo. Entonces la prueba evita cuidadosamente escribir cualquier código que agregue 10 a cualquier cosa, en la prueba que plus() puede agregar 10 a las cosas. Todavía confiamos en los valores del ciclo inicial verificado por el programador, por supuesto.
3 Warbo 07/28/2017
Solo quiero señalar que incluso si está escribiendo pruebas después del hecho, sigue siendo una buena idea verlos fallar; encuentre alguna parte del código que parezca crucial para lo que sea que esté trabajando, modifíquelo un poco (por ejemplo, reemplace un + con un -, o lo que sea), ejecute las pruebas y mire si fallan, deshaga el cambio y mire cómo lo pasan. Muchas veces lo he hecho, la prueba no falla, por lo que es peor que inútil: no solo no está probando nada, sino que me está dando una falsa seguridad de que algo está siendo probado.

Victor Cejudo 07/25/2017.

Algunas veces algunos ejemplos sobre TDD pueden ser engañosos. Como otras personas han señalado anteriormente, el código que se escribe para pasar las pruebas es el código real.

Pero no piense que el código real parece mágico, eso está mal. Necesita comprender mejor lo que quiere lograr y luego debe elegir la prueba en consecuencia, comenzando por los casos más fáciles y los casos de esquina.

Por ejemplo, si necesita escribir un lexer, comience con una cadena vacía, luego con un grupo de espacios en blanco, luego un número, luego con un número rodeado de espacios en blanco, luego un número incorrecto, etc. Estas pequeñas transformaciones lo llevarán a el algoritmo correcto, pero no salta del caso más fácil a un caso muy complejo elegido tontamente para obtener el código real.

Bob Martin lo explica perfectamente aquí .


CandiedOrange 07/25/2017.

La parte refactorizada se limpia cuando estás cansado y quieres irte a casa.

Cuando está por agregar una función, la parte de refactor es lo que cambia antes de la próxima prueba. Usted refactoriza el código para dejar espacio para la nueva característica. Haga esto cuando know cuál será esa nueva característica. No cuando solo lo estás imaginando.

Esto puede ser tan simple como cambiar el nombre de GreetImpl a GreetWorld antes de crear una clase GreetMom (después de agregar una prueba) para agregar una función que imprimirá "Hola mamá".


graeme 07/27/2017.

Pero el código real aparecería en la etapa de refactorización de la fase TDD. Es decir, el código que debería ser parte de la versión final.

Las pruebas se deben ejecutar cada vez que realice un cambio.

El lema del ciclo de vida de TDD sería: REFORZADOR VERDE ROJO

RED : escriba las pruebas

GREEN : Haga un intento honesto de obtener un código funcional que pase las pruebas lo más rápido posible: código duplicado, variables misteriosamente pirateadas de orden superior, etc.

REFACTOR : Limpie el código, nombre adecuadamente las variables. SECAR el código.

5 comments
5 mcottle 07/25/2017
Sé lo que dices sobre la fase "verde", pero implica que los valores de retorno de cableado para pasar las pruebas podrían ser apropiados. En mi experiencia, "Verde" debería ser un intento honesto de hacer código de trabajo para cumplir con el requisito, puede no ser perfecto, pero debe ser tan completo y "expedible" como el desarrollador puede gestionar en un primer paso. La refabricación probablemente se realice mejor después de haber realizado más desarrollo y los problemas con el primer pase se vuelven más evidentes y surgen oportunidades para DRY.
graeme 07/25/2017
@mcottle considero que todo esto forma parte de la misma tarea. hazlo, luego límpialo. Deben realizarse nuevas refactorizaciones a medida que pasa el tiempo como parte de otras tareas.
1 Bryan Boettcher 07/25/2017
@mcottle: es posible que se sorprenda de cuántas implementaciones de un repositorio de solo obtener pueden ser valores codificados en la base de código. :)
6 Kaz 07/25/2017
¿Por qué escribiría un código de mierda y lo limpiaría, cuando puedo producir un buen código de calidad de producción casi tan rápido como puedo escribir? :)
1 Kaz 07/27/2017
@TimothyTruckle ¿Qué significa 50 minutos para encontrar el cambio más simple posible, pero solo 5 para encontrar el segundo cambio más simple posible? ¿Vamos con el segundo más simple o seguimos buscando el más simple?

Timothy Truckle 07/27/2017.

¿Cuándo escribes el código "real" en TDD?

La fase red es donde write código.

En la fase de refactoring , el objetivo principal es delete código.

En la fase red , haces cualquier cosa para que la prueba pase as quick as possible y at any cost . Ignoras por completo lo que alguna vez has escuchado sobre buenas prácticas de codificación o patrones de diseño similares. Hacer la prueba verde es todo lo que importa.

En la fase de refactoring , usted limpia el desastre que acaba de hacer. Ahora primero verá si el cambio que acaba de realizar es del tipo que se encuentra más arriba en la lista de Prioridad de Transformación y si hay alguna duplicación de código, puede eliminarlo aplicando un patrón de diseño.

Finalmente, mejora la legibilidad cambiando el nombre de identificadores y extrayendo magic numbers y / o cadenas literales a constantes.


No es rojo-refactor, es rojo-verde-refactor. - Rob Kinyon

Gracias por señalar esto.

Entonces es la fase green donde escribes el real code

En la fase red escribes la executable specification ...

2 comments
Rob Kinyon 07/27/2017
No es rojo-refactor, es rojo-verde-refactor. El "rojo" es que lleva su banco de pruebas del verde (todas las pruebas pasan) al rojo (una prueba falla). El "verde" es el lugar en el que descuidadamente lleva su banco de pruebas de rojo (una prueba falla) a verde (pasan todas las pruebas). El "refactor" es donde tomas tu código y lo haces bonito mientras pasas todas las pruebas.
Timothy Truckle 07/27/2017
@RobKinyon Gracias, actualizó la respuesta.

Robert Andrzejuk 07/27/2017.

Está escribiendo Real Code todo el tiempo.

En cada paso, está escribiendo código para satisfacer las condiciones que Su código satisfará a las personas que llaman en el futuro de Su código (que puede ser Usted o no ...).

Piensas que no estás escribiendo real código útil ( real ), porque en un momento podrías refactorizarlo.

Code-Refactoring es el proceso de reestructuración de código informático existente, que cambia el factoring, sin cambiar su comportamiento externo.

Lo que esto significa es que a pesar de que está cambiando el código, las condiciones en que se cumplió el código no se modifican. Y las comprobaciones ( tests ) que implementó para verificar que su código ya está allí para verificar si sus modificaciones cambiaron algo. Entonces el código que escribió todo el tiempo está ahí, solo de una manera diferente.

Otra razón por la que podría pensar que no es un código real es que está haciendo ejemplos en los que el programa final ya puede ser visto por usted. Esto es muy bueno, ya que muestra que usted tiene conocimiento sobre el domain que está programando.
Pero muchas veces los programadores están en un domain que es new , unknown para ellos. No saben cuál será el resultado final y TDD es una technique para escribir programas paso a paso, documentando nuestro knowledge sobre cómo debería funcionar este sistema y verificando que nuestro código funciona de esa manera.

Cuando leí The Book (*) en TDD, para mí la característica más importante que se destacó fue la lista: TODO. Me demostró que, TDD es también una técnica para ayudar a los desarrolladores a enfocarse en una cosa a la vez. Así que esta también es una respuesta a su pregunta How much Real code to write ? Diría suficiente código para enfocarme en 1 cosa a la vez.

(*) "Desarrollo controlado por prueba: por ejemplo" por Kent Beck

1 comments
2 Robert Andrzejuk 07/27/2017
"Desarrollo basado en pruebas: por ejemplo" por Kent Beck

Zenilogix 07/31/2017.

No está escribiendo código para hacer que sus pruebas fallen.

Usted escribe sus pruebas para definir qué aspecto debería tener el éxito, que inicialmente deberían fallar porque aún no ha escrito el código que pasará.

El objetivo de escribir ensayos que fracasan inicialmente es hacer dos cosas:

  1. Cubre todos los casos: todos los casos nominales, todos los casos extremos, etc.
  2. Valida tus pruebas. Si solo los ve pasar, ¿cómo puede estar seguro de que informarán de manera confiable una falla cuando ocurra?

El punto detrás del refactor rojo-verde es que escribir las pruebas correctas primero le da la confianza de saber que el código que escribió para pasar las pruebas es correcto, y le permite refactorizar con la confianza de que sus pruebas le informarán tan pronto como sea posible. algo se rompe, por lo que puede volver inmediatamente y arreglarlo.

En mi propia experiencia (C # /. NET), pure-test-first es un ideal inalcanzable, porque no se puede compilar una llamada a un método que aún no existe. Así que "probar primero" se trata de codificar interfaces e implementaciones de stubbing primero, luego escribir pruebas contra los stubs (que inicialmente fallarán) hasta que los stubs se desarrollen correctamente. No estoy escribiendo el "código de error", simplemente construyendo de los talones.


Zan Lynx 07/27/2017.

Creo que puede confundirse entre pruebas unitarias y pruebas de integración. Creo que también puede haber pruebas de aceptación, pero eso depende de su proceso.

Una vez que haya probado todas las pequeñas "unidades", las probará todas ensambladas o "integradas". Por lo general, es un programa completo o una biblioteca.

En el código que he escrito, la integración prueba una biblioteca con varios programas de prueba que leen datos y los envían a la biblioteca, luego verifican los resultados. Entonces lo hago con hilos. Luego lo hago con hilos y tenedor () en el medio. Luego lo ejecuto y mato -9 después de 2 segundos, luego lo inicio y verifico su modo de recuperación. Lo confundí. Lo torturo de muchas maneras.

Todo eso también está probando, pero no tengo una bonita pantalla roja / verde para los resultados. O tiene éxito, o exploro unas pocas miles de líneas de código de error para descubrir por qué.

Ahí es donde se prueba el "código real".

Y solo pensé en esto, pero tal vez no sabes cuándo se supone que termines de escribir pruebas unitarias. Has terminado de escribir pruebas unitarias cuando tus pruebas ejercen todo lo que especificaste que debería hacer. A veces puede perder la pista de eso entre todos los casos de manipulación de errores y bordes, por lo que es posible que desee hacer un buen grupo de prueba de pruebas de ruta felices que simplemente vayan directamente a través de las especificaciones.

1 comments
Peter Mortensen 07/27/2017
(its = possessive, it = "it is" o "it have". Ver por ejemplo How to Use Its and It's .)

user3791372 07/27/2017.

En respuesta al título de la pregunta: "¿Cuándo escribes el código" real "en TDD?", La respuesta es: "casi nunca" o "muy lentamente".

Suenas como un estudiante, entonces responderé como si estuviera asesorando a un estudiante.

Vas a aprender muchas "teorías" y "técnicas" de codificación. Son excelentes para pasar el tiempo en cursos de estudiantes sobrevalorados, pero de muy poco beneficio para usted que no podría leer en un libro en la mitad del tiempo.

El trabajo de un codificador es únicamente para producir código. Código que funciona realmente bien. Es por eso que usted, el codificador, planifica el código en su mente, en papel, en una aplicación adecuada, etc., y planea evitar posibles fallas / agujeros de antemano al pensar lógica y lateralmente antes de la codificación.

Pero necesita saber cómo romper su aplicación para poder diseñar un código decente. Por ejemplo, si no sabía acerca de Little Bobby Table (xkcd 327), probablemente no estaría desinfectando sus entradas antes de trabajar con la base de datos, por lo que no podría proteger sus datos en torno a ese concepto.

TDD es solo un flujo de trabajo diseñado para minimizar los errores en tu código al crear pruebas de lo que podría salir mal antes de codificar tu aplicación porque la codificación puede ser exponencialmente difícil cuanto más código introduzcas y olvidas los errores que alguna vez pensaste. Una vez que piensas que has terminado tu aplicación, ejecutas las pruebas y el boom, con suerte los errores se detectan con tus pruebas.

TDD no es, como algunas personas creen, escribir una prueba, aprobarla con un código mínimo, escribir otra prueba, obtener esa aprobación con un código mínimo, etc. En cambio, es una forma de ayudarlo a codificar con confianza. Este ideal de código de refactorización continuo para que funcione con las pruebas es idiota, pero es un concepto agradable entre los estudiantes porque les hace sentir muy bien cuando agregan una nueva función y todavía están aprendiendo cómo codificar ...

Por favor, no caiga en esta trampa y vea su función de codificación de lo que es: el trabajo de un codificador es únicamente producir código. Código que funciona realmente bien. Ahora, recuerda que estarás en el reloj como un codificador profesional, y a tu cliente no le importará si escribiste 100.000 afirmaciones, o 0. Simplemente quieren un código que funcione. De verdad, de hecho.

5 comments
3 johnny 07/25/2017
Ni siquiera estoy cerca de un estudiante, pero leo y trato de aplicar buenas técnicas y ser profesional. Entonces, en ese sentido, soy un "estudiante". Solo hago preguntas muy básicas porque así soy yo. Me gusta saber exactamente por qué estoy haciendo lo que estoy haciendo. Lo importante del asunto. Si no entiendo eso, no me gusta y empiezo a hacer preguntas. Necesito saber por qué, si voy a usarlo. TDD parece intuitivamente bueno en algunos aspectos, como saber lo que necesita crear y pensar detenidamente, pero la implementación fue difícil de entender. Creo que tengo una mejor comprensión ahora.
4 Sean Burton 07/27/2017
Esas son las reglas de TDD. Eres libre de escribir el código como quieras, pero si no sigues esas tres reglas, no estarás haciendo TDD.
2 user3791372 07/27/2017
"Reglas" de una persona? TDD es una sugerencia para ayudarlo a codificar, no a una religión. Es triste ver a tantas personas adherirse a una idea tan analmente. Incluso el origen de TDD es controvertido.
2 Alex 07/28/2017
@ user3791372 TDD es un proceso muy estricto y claramente definido. Incluso si muchos piensan que eso es solo decir "Haz algunas pruebas cuando estás programando", no es así. Intentemos no mezclar los términos aquí, esta pregunta es sobre el proceso TDD, no las pruebas generales.

Related questions

Hot questions

Language

Popular Tags