Soy un nuevo programador (solo he estado aprendiendo durante aproximadamente un año) y, en mi objetivo de mejorar, recientemente he aprendido sobre TDD. Quería adquirir el hábito de usarlo, ya que parece muy útil. Quería verificar y asegurarme de que lo estoy usando correctamente.
Que estoy haciendo:
- Piensa en un nuevo método que necesito.
- Crea una prueba para ese método.
- Prueba fallida
- Método de escritura.
- Pasar el examen.
- Método refactorizador.
- Repetir.
Estoy haciendo esto para CADA método que escribo, ¿hay algunos con los que no debería molestarme? Más tarde, generalmente pienso en una forma de probar mis métodos ya existentes de una manera o situación diferente. ¿Debo hacer estas nuevas pruebas en las que pienso, o ya que cada método ya tiene una prueba propia, no debería molestarme? ¿Puedo probar MÁS mi código? Supongo que es mi principal preocupación preguntar esto.
EDITAR
Además, esto era algo que me preguntaba. Al hacer algo como hacer una GUI, ¿sería necesario TDD en esa situación? Personalmente, no puedo pensar en cómo escribiría pruebas para eso.
Respuestas:
Lo que está describiendo como un flujo de trabajo no es, en mi opinión, el espíritu de TDD.
La sinopsis del libro de Kent Becks en Amazon dice:
TDD práctico
Pruebas formales automatizadas, especialmente Pruebas unitarias, cada método de cada clase es tan malo como un antipatrón y no prueba nada. Hay un equilibrio para tener. ¿Estás escribiendo pruebas unitarias para cada
setXXX/getXXX
método, también son métodos!Además, las pruebas pueden ayudar a ahorrar tiempo y dinero, pero no olvide que cuestan tiempo y dinero desarrollarlas y que son código, por lo que cuestan tiempo y dinero mantenerlas. Si se atrofian por falta de mantenimiento, se convierten en una responsabilidad más que un beneficio.
Como todo esto, hay un equilibrio que no puede ser definido por nadie más que por ti mismo. Cualquier dogma de cualquier manera es probablemente más incorrecto que correcto.
Una buena métrica es el código que es crítico para la lógica del negocio y está sujeto a modificaciones frecuentes basadas en los requisitos cambiantes. Esas cosas necesitan pruebas formales que estén automatizadas, eso sería un gran retorno de la inversión.
Va a ser muy difícil encontrar muchas tiendas profesionales que funcionen de esta manera. Simplemente no tiene sentido comercial gastar dinero probando cosas que, para todos los fines prácticos, nunca cambiarán después de realizar una simple prueba de humo. Escribir pruebas unitarias automatizadas formales para
.getXXX/.setXXX
métodos es un excelente ejemplo de esto, una completa pérdida de tiempo.Ver también esta respuesta .
fuente
setXXX/getXXX
no son necesarias :)Estas muy cerca. Intenta pensar de esta manera ligeramente diferente.
No cree automáticamente getters y setters para cada propiedad . No piense en un método completo y escriba las pruebas para cubrir toda la funcionalidad . Intente encapsular las propiedades dentro de la clase y escriba métodos para proporcionar el comportamiento que necesita. Deje que sus métodos evolucionen hacia un buen diseño en lugar de tratar de planificarlos por adelantado. Recuerde que TDD es un proceso de diseño, no un proceso de prueba. La ventaja que tiene sobre otros procesos de diseño es que deja atrás un flujo de pruebas de regresión automatizadas, en lugar de un pedazo de papel que arroje a la basura.
Además, recuerde las tres reglas de TDD del tío Bob .
fuente
Pocas cosas para agregar a las respuestas de otros:
Existe una prueba excesiva. Desea asegurarse de que las pruebas de su unidad se superpongan lo menos posible. No tiene sentido que múltiples pruebas verifiquen las mismas condiciones en el mismo fragmento de código. Por otro lado, cuando refactorice su código de producción y tenga muchas pruebas que se superpongan a esa sección, tendrá que regresar y corregir todas esas pruebas. Mientras que si no se superponen, un cambio interrumpirá a lo sumo una sola prueba.
Solo porque pensaste en una mejor manera de escribir un examen, no volvería allí y comenzaría a reescribirlo. Esto se remonta a las personas que siguen escribiendo y reescribiendo la misma clase / función porque intentan que sea perfecta. Nunca será perfecto, así que sigue adelante. Cuando descubra un método mejor, manténgalo en su mente (o agréguelo a los comentarios de la prueba). La próxima vez que esté allí, y vea un beneficio inmediato de cambiar a la nueva forma, ese es el momento de refactorizar. De lo contrario, si la función está terminada y usted siguió adelante y todo funciona, déjelo funcionando.
TDD se enfoca en entregar valor inmediato, no simplemente en asegurarse de que cada función sea comprobable. Cuando agregue funcionalidad, comience preguntando "qué necesita el cliente". Luego defina una interfaz para darle al cliente lo que necesita. Luego implemente lo que sea necesario para que la prueba pase. TDD es casi como probar escenarios de casos de uso (incluidos todos los "qué pasa si"), en lugar de simplemente codificar funciones públicas y probar cada una.
Preguntaste sobre probar el código GUI. Busque los patrones "Diálogo humilde" y "MVVM". La idea detrás de ambos es crear un conjunto de clases de "modelo de vista", que en realidad no tienen una lógica específica de UI. Sin embargo, estas clases tendrán toda la lógica de negocios que generalmente forma parte de su interfaz de usuario y estas clases deben ser 100% comprobables. Lo que queda es un shell de interfaz de usuario muy delgado y sí, generalmente ese shell se queda sin cobertura de prueba, pero en ese punto casi no debería tener lógica.
Si tiene una gran parte del código existente, como pocos sugirieron, no debe comenzar a agregar pruebas unitarias absolutamente en todas partes. Te llevará una eternidad y no obtendrás beneficios al agregar pruebas unitarias al 80% de las clases que son estables y no cambiarán en el futuro cercano (o no tan cercano). Sin embargo, para un nuevo trabajo, encuentro que usar el desarrollo TDD con TODO el código es extremadamente beneficioso. No solo terminas con una suite con pruebas automatizadas cuando terminas, sino que el desarrollo real tiene enormes beneficios:
fuente
Hay algunos métodos que no se están probando, a saber, esas pruebas. Sin embargo, hay algo que decir sobre algunas pruebas que se agregan después de que se ha escrito el código inicial, como las condiciones de contorno y otros valores, de modo que puede haber múltiples pruebas en un solo método.
Si bien puede probar en exceso su código, eso generalmente ocurre cuando alguien quiere probar cada posible permutación de entradas que no suena como lo que está haciendo. Por ejemplo, si tiene un método que toma un carácter, ¿escribe una prueba para cada valor posible que pueda ingresarse? Ahí sería donde tendrías una sobreevaluación, OMI.
fuente
Generalmente lo estás haciendo bien.
Las pruebas son código. Entonces, si puede mejorar la prueba, continúe y refactorícela. Si cree que se puede mejorar una prueba, continúe y cámbiela. No tenga miedo de reemplazar una prueba con una mejor.
Recomiendo al probar su código, evite especificar cómo se supone que el código debe hacer lo que está haciendo. Las pruebas deben observar los resultados de los métodos. Esto ayudará con la refactorización. Algunos métodos no necesitan ser probados explícitamente (es decir, getters y setters simples) porque los usará para verificar los resultados de otras pruebas.
fuente
Mi opinión sobre TDD es que las herramientas han creado un mundo de desarrolladores de estilo 'apuntar y hacer clic'. El hecho de que las herramientas creen un trozo de prueba para cada método no significa que deba escribir pruebas para cada método. Algunas personas están 'renombrando' TDD como BDD (desarrollo impulsado por el comportamiento) donde las pruebas son mucho más amplias y tienen la intención de probar el comportamiento de la clase, no cada método poco complicado.
Si diseña sus pruebas para evaluar la clase como está destinada a ser utilizada, entonces comienza a obtener algunos beneficios, especialmente a medida que comienza a escribir pruebas que ejercen un poco más que cada método, especialmente cuando comienza a probar la interacción de esos métodos. Supongo que podrías pensar en ello como escribir pruebas para una clase, en lugar de métodos. En cualquier caso, aún debe escribir 'pruebas de aceptación' que ejerciten la combinación de métodos para asegurarse de que no haya contradicciones o conflictos en la forma en que se usan juntos.
No confunda TDD con las pruebas, no lo es. TDD está diseñado para que escriba código para ejercer sus requisitos, no para probar los métodos. Es un punto sutil pero importante que a menudo se pierde en las personas que escriben ciegamente códigos de prueba para cada método. Es que debes escribir pruebas que aseguren que tu código haga lo que quieres que haga, no que el código que escribiste funcione como se supone que debe hacerlo.
Hay algunos buenos enlaces a la derecha sobre BDD v TDD. Échales un vistazo.
fuente
Cuando comienza a aprender TDD, sí, debe seguir ciegamente el enfoque dogmático de no escribir una sola línea de código, excepto para aprobar una prueba reprobatoria y escribir solo una prueba suficiente para fallar (y fallar por la razón correcta / esperada) .
Una vez que haya aprendido de qué se trata TDD, ENTONCES puede decidir que ciertos tipos de cosas no valen la pena probar. Este es el mismo enfoque que debes seguir para todo, y las artes marciales japonesas llaman a esto " shuhari ". (El enlace también explica cómo uno puede progresar a través de las etapas de aprendizaje sin un maestro, que es, sospecho, cómo la mayoría de la gente tiene que aprender).
fuente
Creo que estás exagerando.
He practicado TDD durante muchos años y, en mi experiencia, cuando TDD se realiza de manera efectiva, obtienes dos beneficios principales:
Proporcionar retroalimentación rápida
Particularmente con lenguajes dinámicos, puedo ejecutar las pruebas relevantes en menos de un segundo. Y tengo observadores del sistema de archivos que ejecutan estas pruebas automáticamente cuando se cambia un archivo fuente en el disco. Por lo tanto, prácticamente no tengo tiempo de espera para las pruebas, e inmediatamente sé si el código que escribí hizo lo esperado. Por lo tanto, TDD conduce a una forma de trabajo muy eficiente.
Habilitar refactorización
Si tiene un buen conjunto de pruebas, puede refactorizar de forma segura, a medida que obtiene nuevos conocimientos sobre cómo debe diseñarse el sistema.
Un buen conjunto de pruebas le permite trasladar la responsabilidad en su código, y aún tener la confianza de que el código funciona como se espera después del traslado. Y debería poder hacer esto con pequeños cambios en el código de prueba.
Si escribe pruebas para cada método en su sistema, lo más probable es que no pueda refactorizar fácilmente su código, cada refactorizador de su código requerirá cambios masivos en el código de prueba. ¿Y puede estar seguro de que el código de prueba todavía funciona como se esperaba? ¿O introdujo accidentalmente un error en el código de prueba, que en consecuencia conduce a un error en el código de producción?
Sin embargo, si, como también se sugiere en la respuesta de pdr , se concentra en el comportamiento en lugar de los métodos al escribir pruebas, tendrá pruebas que requerirán muchos menos cambios al refactorizar el sistema.
O como dice Ian Cooper en esta presentación (cité de memoria, por lo que podría no estar correctamente citado):
fuente
Debes probar todos los métodos públicos .
El problema aquí es que si sus métodos públicos son muy pequeños, probablemente exponga demasiada información. La práctica común de exponer cada propiedad como
getXXX()
realmente rompe la encapsulación.Si sus métodos públicos son realmente el comportamiento de la clase, entonces debe probarlos. Si no, no son buenos métodos públicos.
EDITAR: la respuesta de pdr es mucho más completa que la mía.
fuente