unit-testing - test - pruebas unitarias python
¿Las pruebas unitarias deben escribirse antes de escribir el código? (20)
Algunos buenos comentarios aquí, pero creo que una cosa es ser ignorado.
escribir pruebas primero impulsa su diseño. Este es un paso importante. Si escribe las pruebas "al mismo tiempo" o "poco después" es posible que se pierda algunos beneficios de diseño de hacer TDD en micro pasos.
Se siente muy cursi al principio, pero es increíble ver cómo se desarrollan las cosas ante tus ojos en un diseño en el que no pensabas originalmente. Lo he visto suceder
TDD es difícil, y no es para todos. Pero si ya acepta las pruebas unitarias, pruébelo durante un mes y vea qué le hace a su diseño y productividad.
Pasa menos tiempo en el depurador y más tiempo pensando en diseño externo. Esas son dos ventajas gigantescas en mi libro.
Sé que uno de los principios definitorios del desarrollo basado en pruebas es que primero se escriben las pruebas de su Unidad y luego se escribe el código para pasar las pruebas unitarias, pero ¿es necesario hacerlo de esta manera?
Descubrí que a menudo no sé qué estoy probando hasta que lo escribí, principalmente porque los últimos dos proyectos en los que he trabajado han evolucionado a partir de una prueba de concepto en lugar de haber sido diseñados.
Intenté escribir mis pruebas unitarias antes y puede ser útil, pero no me parece natural.
Antes, durante y después. Antes es parte de la especificación, el contrato, la definición del trabajo Durante es cuando se descubren casos especiales, datos incorrectos, excepciones durante la implementación. Después es mantenimiento, evolución, cambio, nuevos requisitos.
Comienzo por cómo me gustaría llamar a mi "unidad" y hacer que compile. me gusta:
picker = Pick.new
item=picker.pick(''a'')
assert item
entonces creo
class Pick
def pick(something)
return nil
end
end
luego sigo usando Pick en mi caso de "prueba" para poder ver cómo me gustaría que se llame y cómo trataría diferentes tipos de comportamiento. Cada vez que me doy cuenta de que podría tener problemas en algunos límites o algún tipo de error / excepción, intento disparar y obtener un nuevo caso de prueba.
Entonces, en resumen. Sí. La relación que hace la prueba antes es mucho más alta que no hacerlo.
Cuando escribe algo que le ayuda a escribir, le ayuda escribir primero todo lo que regularmente verificaría y luego escribir esas características. Más veces, entonces esas características no son las más importantes para la pieza de software que está escribiendo. Ahora, en el otro lado, no hay balas de plata y las cosas nunca deben seguirse al pie de la letra. El juicio del desarrollador juega un papel importante en la decisión de usar el desarrollo impulsado por prueba versus el último desarrollo de prueba.
Dirigí equipos de desarrollo durante los últimos 6-7 años. Lo que sí puedo decir con certeza es que, como desarrollador y desarrolladores con los que he trabajado, la diferencia en la calidad del código es enorme si sabemos dónde encaja nuestro código en el panorama general.
Test Driven Development (TDD) nos ayuda a responder "¿Qué?" antes de responder "¿Cómo?" y hace una gran diferencia.
Entiendo por qué puede haber temores sobre no seguirlo en el tipo de trabajo de desarrollo / arquitecto de PoC. Y tiene razón, puede que no tenga todo el sentido seguir este proceso. Al mismo tiempo, me gustaría enfatizar que TDD es un proceso que cae en la Fase de Desarrollo (sé que suena obsoleto, pero entiendes el punto :) cuando las especificaciones de bajo nivel son claras.
Escribir las pruebas primero define cómo se verá tu código, es decir, tiende a hacer que tu código sea más modular y comprobable, por lo que no creas un método de "inflado" con una funcionalidad muy compleja y superpuesta. Esto también ayuda a aislar todas las funciones básicas en métodos separados para una prueba más sencilla.
He estado programando durante 20 años, y prácticamente nunca he escrito una línea de código en la que no realicé algún tipo de prueba de unidad. Honestamente, sé que la gente lo hace todo el tiempo, pero ¿cómo alguien puede enviar un línea de código que no ha tenido algún tipo de ejecución de prueba está más allá de mí.
A menudo, si no hay un marco de prueba en su lugar, simplemente escribo un main () en cada clase que escribo. Agrega un pequeño fragmento a su aplicación, pero alguien siempre puede eliminarlo (o comentarlo) si lo desean, supongo. Realmente me gustaría que hubiera solo un método de prueba () en tu clase que compilara automáticamente las compilaciones de lanzamiento. Me encanta que mi método de prueba esté en el mismo archivo que mi código ...
Así que he hecho desarrollo basado en pruebas y desarrollo probado. Puedo decirte que TDD realmente puede ayudar cuando eres un programador principiante. Le ayuda a aprender a ver su código "desde afuera", que es una de las lecciones más importantes que un programador puede aprender.
TDD también te ayuda a ponerte en marcha cuando estás atascado. Puedes escribir una pieza muy pequeña que sabes que tu código tiene que hacer, luego ejecutarla y arreglarla, se vuelve adictivo.
Por otro lado, cuando agregas código existente y sabes exactamente lo que quieres, es un lanzamiento. Su "Otro código" a menudo prueba su nuevo código en su lugar. Aún debe asegurarse de probar cada ruta, pero obtiene una buena cobertura simplemente ejecutando las pruebas desde el front-end (excepto en los idiomas dinámicos, para aquellos que realmente deberían tener pruebas unitarias para todo lo que sea).
Por cierto, cuando estaba en un proyecto bastante grande de Ruby / Rails, teníamos un porcentaje muy elevado de cobertura de prueba. Refactorizamos una clase de modelo principal y central en dos clases. Nos habría llevado dos días, pero con todas las pruebas que tuvimos que refactorizar terminó cerca de dos semanas. Las pruebas NO son completamente gratis.
Las directivas son sugerencias sobre cómo se pueden hacer cosas para mejorar la calidad general o la productividad o incluso ambos productos finales. De ninguna manera son leyes para ser obedecidas, menos te aprietas en un instante por el dios de la práctica de codificación adecuada.
Aquí está mi compromiso con la toma y la encontré bastante útil y productiva.
Por lo general, la parte más difícil de acertar son los requisitos y justo detrás de la usabilidad de su clase, API, paquete ... Entonces es la implementación real.
- Escribe tus interfaces (cambiarán, pero recorrerán un largo camino para saber QUÉ se debe hacer)
- Escribe un programa simple para usar las interfaces (estúpido principal). Esto ayuda mucho a determinar el CÓMO se va a utilizar (vuelva a 1 tan a menudo como sea necesario)
- Escribir pruebas en la interfaz (El bit que integé desde TDD, de nuevo vuelve a 1 tantas veces como sea necesario)
- escribe el código real detrás de las interfaces
- escriba pruebas en las clases y la implementación real, use una herramienta de cobertura para asegurarse de no olvidar las rutas de ejecución de weid
Entonces, sí, escribo pruebas antes de codificar, pero nunca antes me di cuenta de lo que hay que hacer con un cierto nivel de detalles. Estas suelen ser pruebas de alto nivel y solo tratan el conjunto como una caja negra. Normalmente permanecerá como pruebas de integración y no cambiará mucho una vez que las interfaces se hayan estabilizado.
Luego, escribo un montón de pruebas (pruebas unitarias) sobre la implementación detrás de esto, estas serán mucho más detalladas y cambiarán a menudo a medida que la implementación evolucione, a medida que se optimice y se amplíe.
¿Es esto estrictamente hablando TDD? Extremo? Ágil...? lo que sea... ? No lo sé, y francamente no me importa. Funciona para mí Lo ajusto según las necesidades y conforme avanza mi comprensión de la práctica del desarrollo de software.
mi 2 centavo
Los escribo al mismo tiempo. Creo el código de esqueleto para la nueva clase y la clase de prueba, y luego escribo una prueba de alguna funcionalidad (que luego me ayuda a ver cómo quiero que se llame al nuevo objeto) y la implemento en el código.
Usualmente, no termino con un código elegante la primera vez, normalmente es bastante hacky. Pero una vez que todas las pruebas estén funcionando, puedes refactorizar hasta que termines con algo bastante limpio, ordenado y que pueda ser sólido como una roca.
No escribo las pruebas de unidad reales primero, pero sí hago una matriz de prueba antes de comenzar a codificar, enumerando todos los escenarios posibles que tendrán que probarse. También hago una lista de casos que tendrán que probarse cuando se realiza un cambio en cualquier parte del programa como parte de una prueba de regresión que cubrirá la mayoría de los escenarios básicos en la aplicación, además de probar completamente el bit de código que cambiado
No siempre, pero creo que realmente ayuda cuando lo hago.
Personalmente, creo que las pruebas unitarias pierden mucha efectividad si no se hacen antes de escribir el código.
El viejo problema de las pruebas es que no importa cuán duro lo pensemos, nunca se nos ocurrirán todos los escenarios posibles para escribir una prueba para cubrir.
Obviamente, las pruebas unitarias no evitan esto por completo, ya que son pruebas restrictivas, ya que solo se observa una unidad de código que no cubre las interacciones entre este código y todo lo demás, pero proporciona una buena base para escribir código limpio que debería al menos restrinja las posibilidades de problemas de interacción entre módulos. Siempre he trabajado según el principio de mantener el código tan simple como sea posible; de hecho, creo que este es uno de los principios clave de TDD.
Así que comenzando con una prueba que básicamente dice que puedes crear una clase de este tipo y construirla, en teoría, escribir una prueba para cada línea de código o al menos cubrir cada ruta a través de una pieza de código en particular. Diseñando sobre la marcha Obviamente, se basa en un diseño inicial bruto producido inicialmente, para darle un marco para trabajar.
Como dices, es muy antinatural para empezar y puede parecer una pérdida de tiempo, pero me he visto de primera mano que vale la pena a la larga cuando aparecen los defectos y muestra los módulos que fueron completamente escritos usando TDD. tienen defectos mucho más bajos en el tiempo que otros.
Recuerde que con la programación extrema sus pruebas son efectivamente su documentación. Entonces, si no sabe lo que está probando, ¿no sabe lo que quiere que su aplicación vaya a hacer?
Puedes comenzar con "Stories", que podría ser algo así como
"Los usuarios pueden obtener una lista de preguntas"
Luego, cuando empiece a escribir código para resolver las pruebas unitarias. Para resolver lo anterior, necesitará al menos una clase de usuario y pregunta. Entonces puedes comenzar a pensar sobre los campos:
"Clase de usuario tiene nombre Dirección de DOB TelNo campos bloqueados"
etc. Espero que ayude.
Astuto
Sí, si estás usando principios verdaderos de TDD. De lo contrario, siempre y cuando estés escribiendo las pruebas unitarias, lo estás haciendo mejor que la mayoría.
En mi experiencia, generalmente es más fácil escribir las pruebas antes que el código, porque al hacerlo así te das una herramienta de depuración simple para usar mientras escribes el código.
Se han realizado estudios que muestran que las pruebas unitarias escritas después de que se haya escrito el código son mejores pruebas. La advertencia es que la gente no tiende a escribirlos después del evento. Entonces TDD es un buen compromiso ya que al menos las pruebas se escriben.
Entonces, si escribes pruebas después de haber escrito el código, bien por ti, te sugiero que te mantengas firme.
Tiendo a encontrar que hago una mezcla. Cuanto más entiendo los requisitos, más pruebas puedo escribir desde el principio. Cuando los requisitos, o mi comprensión del problema, son débiles, tiendo a escribir pruebas después.
TDD no se trata de las pruebas, sino de cómo las pruebas controlan tu código. Así que, básicamente, estás escribiendo pruebas para permitir que una arquitectura evolucione de forma natural (¡y no olvides refactorizar! De lo contrario, no obtendrás muchos beneficios de ella). Que tenga un arsenal de pruebas de regresión y documentación ejecutable después es un buen efecto secundario, pero no la razón principal detrás de TDD.
Entonces mi voto es: prueba primero
PD: ¡Y no, eso no significa que no tengas que planificar tu arquitectura antes, pero que puedas replantearte si las pruebas te dicen que lo hagas!
Tiendo a escribirlos mientras escribo mi código. Como máximo, escribiré las pruebas para saber si la clase / módulo existe antes de escribirlo.
No planifico lo suficiente con tanto detalle para escribir una prueba antes que el código que va a probar.
No sé si esto es un defecto en mi pensamiento o método o simplemente TIMTOWTDI.
No estoy seguro, pero según su descripción, creo que podría haber un malentendido sobre lo que realmente significa "probar primero". No significa que primero escriba todas sus pruebas. Significa que tienes un ciclo muy apretado de
- escribe una prueba única y mínima
- haga pasar la prueba escribiendo el código de producción mínimo necesario
- escribe la próxima prueba que fallará
- haga pasar todas las pruebas existentes cambiando el código de producción existente de la manera más simple posible
- refactorizar el código (¡prueba y producción!) para que no contenga duplicación y sea expresivo
- continúa con 3. hasta que no puedas pensar en otra prueba sensata
Un ciclo (3-5) generalmente solo toma un par de minutos. Usando esta técnica, realmente evoluciona el diseño mientras escribe las pruebas y el código de producción en paralelo. No hay mucho diseño inicial involucrado en absoluto.
Sobre la cuestión de si es "necesario" - no, obviamente no lo es. Ha habido proyectos innumerables exitosos sin hacer TDD. Pero existe una fuerte evidencia de que el uso de TDD generalmente conduce a una calidad significativamente mayor, a menudo sin impacto negativo en la productividad. ¡Y es divertido también!
Ah, y considerando que no se siente "natural", es solo una cuestión de a lo que estás acostumbrado. Conozco personas que son bastante adictas a obtener una barra verde (el típico signo xUnit para "pasar todas las pruebas") cada dos minutos.
Hay tantas respuestas ahora y todas son diferentes. Esto se asemeja perfectamente a la realidad que existe. Todos lo hacen de manera diferente. Creo que hay un gran malentendido sobre las pruebas unitarias. Me parece que la gente escuchó sobre TDD y dijeron que es bueno. Luego comenzaron a escribir pruebas unitarias sin realmente entender qué es realmente TDD. Acaban de obtener la parte "oh sí, tenemos que escribir pruebas" y están de acuerdo. También escucharon sobre esto "debes escribir tus pruebas primero" pero no toman esto en serio.
Creo que es porque no entienden los beneficios de la prueba primero que a su vez solo se puede entender una vez que lo haya hecho de esta manera durante algún tiempo. Y siempre parecen encontrar 1.000.000 de excusas por las que no les gusta escribir las pruebas primero. Porque es muy difícil cuando descubro cómo encajarán todas las cosas, etc. etc. En mi opinión, todo es excusa para que se escondan de su incapacidad para disciplinarse una vez, probar el enfoque de probar primero y comenzar a ver los beneficios.
Lo más ridículo si comienzan a discutir "No estoy convencido de esta prueba, primero, pero nunca lo hice así" ... genial ...
Me pregunto de dónde provienen las pruebas unitarias. Porque si el concepto realmente se origina en TDD, es ridículo cómo la gente se equivoca.
Creo que escribir la prueba primero ayuda a definir lo que el código realmente debería hacer. Demasiadas veces las personas no tienen una buena definición de lo que se supone que debe hacer el código o cómo debería funcionar. Simplemente comienzan a escribir y inventar a medida que avanzan. La creación de la prueba primero te hace enfocarte en lo que hará el código.