¿Son realmente útiles las pruebas unitarias? [cerrado]

98

Me acabo de graduar con un título en CS y actualmente tengo un trabajo como Desarrollador Junior .NET (C #, ASP.NET y formularios web). Cuando aún estaba en la universidad, el tema de las pruebas unitarias se cubrió, pero nunca vi realmente los beneficios. Entiendo lo que se supone que debe hacer, es decir, determinar si un bloque de código es apto o no para su uso. Sin embargo, nunca antes tuve que escribir una prueba unitaria, ni sentí la necesidad de hacerlo.

Como ya mencioné, generalmente estoy desarrollando con formularios web ASP.NET, y recientemente he estado pensando en escribir algunas pruebas unitarias. Pero tengo algunas preguntas sobre esto.

He leído que las pruebas unitarias a menudo se realizan escribiendo "simulacros". Si bien entiendo este concepto, parece que no puedo entender cómo se supone que debo escribir simulacros para sitios web que son completamente dinámicos y donde casi todo depende de los datos que provienen de una base de datos. Por ejemplo: utilizo muchos repetidores que tienen eventos ItemDataBound, etc. (de nuevo dependiendo de los datos que son "desconocidos").

Entonces, la pregunta número 1: ¿Escribir pruebas unitarias para formularios web ASP.NET es algo que se hace con frecuencia y, si es así, cómo resuelvo el problema del "entorno dinámico"?

Cuando estoy desarrollando paso por muchas pruebas y errores. Eso no significa que no sé lo que estoy haciendo, pero quiero decir que generalmente escribo un código, presiono Ctrl F5y veo qué sucede. Si bien este enfoque hace el trabajo la mayor parte del tiempo, a veces tengo la sensación de que estoy un poco despistado (debido a mi poca experiencia). A veces también pierdo mucho tiempo así.

Entonces, pregunta número 2: ¿Me aconsejarían que comenzara a escribir pruebas unitarias? Creo que podría ayudarme en la implementación real, pero nuevamente siento que podría retrasarme.

Jane Doe
fuente
1
Me gustaría decir que el otro lado de esto es que algunos lugares los requieren como práctica. Ahora estoy en un lugar donde no se nos permite registrar el código a menos que esté cubierto por las pruebas unitarias. Por lo tanto, es importante tener en cuenta que, incluso si no cree en ellos, es posible que deba hacerlo en el futuro. Creo que es una habilidad útil para aprender y tener en tu arsenal. Muchas veces encontraré pequeños errores y percances en mi código al hacer las pruebas, casi una pequeña sesión de control de calidad contigo mismo.
Adam
99
¿Cómo cubriste exactamente las pruebas unitarias sin escribir ninguna prueba unitaria? ¿Era esta una de esas escuelas de "califícate" o "diseña tu propio plan de estudios"?
JeffO
44
Las pruebas unitarias son cuestionables: ideal para idiomas dinámicos, menos útil cuanto más estricto sea su idioma, pero HAGA PRUEBAS. No tienen que ser pruebas unitarias, pero realmente debería tener pruebas de integración que pueda ejecutar con JUnit, son muy útiles.
Bill K
13
-1 Lo siento, estoy a favor de buenos argumentos, incluso si no estoy de acuerdo, pero esto es simplemente incorrecto. Nadie afirma que "las pruebas unitarias son para detectar errores en el nuevo código", por lo que es un error: las pruebas unitarias son para detectar regresiones . Y la cita de Dijkstra se saca de contexto: el contexto es que las pruebas no tienen sentido si tiene una especificación formal de su problema .
sleske
99
"las pruebas unitarias son para atrapar regresiones". No. Las pruebas automatizadas son para detectar regresiones. Las regresiones requieren invariablemente que se realicen las mismas pruebas cientos de veces, por lo que vale la pena automatizarlas. Desafortunadamente, muchas de las respuestas y comentarios sobre esta pregunta realmente están tratando el tema "¿Son útiles las pruebas automatizadas?". Las pruebas unitarias pueden ser una forma de prueba automatizada, pero tienen un enfoque completamente diferente. Ciertamente considero que las pruebas automatizadas valen su peso en oro, pero eso no debería usarse como argumento para justificar las pruebas unitarias (o TDD para el caso).
njr101

Respuestas:

124

En mi opinión: sí lo son, y sí deberías.

  1. Le dan confianza en los cambios que realiza (todo lo demás sigue funcionando). Esta confianza es lo que necesita para moldear el código, de lo contrario podría tener miedo de cambiar las cosas.

  2. Mejoran tu código; La mayoría de los errores simples se detectan temprano con las pruebas unitarias. Detectar errores temprano y solucionarlos siempre es más barato que corregirlos más tarde, por ejemplo, cuando la aplicación está en producción.

  3. Sirven como documentación para otros desarrolladores sobre cómo funciona su código y cómo usarlo.

El primer problema que enfrenta es que ASP.NET en sí mismo no lo ayuda a escribir pruebas unitarias, en realidad funciona en su contra. Si tiene alguna opción, comience a usar ASP.NET MVC , que se creó teniendo en cuenta las pruebas unitarias. Si no puede usar ASP.NET MVC, debe usar el patrón MVP en ASP.NET para que al menos pueda probar su lógica fácilmente.

Además de eso, solo necesita dominar las pruebas unitarias de escritura. Si practica TDD, su código se crea de manera comprobable, en otras palabras, agradable y limpio.

Te aconsejaría que practiques y pares el programa. Mientras leo:

O, para una primera visión general:

KeesDijk
fuente
44
Habiendo comenzado en las pruebas unitarias, tendría que estar de acuerdo. No solo es un buen hábito y muy útil combinado con un enfoque TDD, sino que minimiza mucho tiempo. No creo que mis proyectos puedan ser tan útiles si no pudiera ejecutar una prueba unitaria y verificar que todo funciona correctamente incluso después de agregar una nueva función o corregir un error. No puedo pensar en hacer pruebas de regresión de otra manera.
kwelch
21
Si las pruebas unitarias funcionan como documentación, hay algo mal. Lectura de 500 líneas de código para comprender cómo funcionan 5 líneas de código al revés.
Codificador
44
@Coder: cuando prueba métodos de nivel superior, implica mucho más de 5 líneas de código.
77
@coder: la documentación de una clase le indica los servicios que proporcionan las instancias de la clase. Le proporciona menos información sobre cómo se usan las instancias de esta clase en el contexto más amplio, es decir, la interacción entre objetos. Las pruebas le dan un código de interacción típico en algunos casos, que ha sido valioso como punto de partida tantas veces que ni siquiera puedo contarlas.
Stefano Borini
21
@Coder: No está documentando lo que hace el código, está documentando los supuestos inherentes a ese código, es decir, por qué y cuándo se supone que debe funcionar. Si los supuestos subyacentes son invalidados por un cambio en el SUT, una o más pruebas unitarias deberían fallar. Esto no reemplaza la documentación de diseño / arquitectura de nivel superior, o incluso documentos XML, pero cubre lo que esas cosas nunca pueden.
Aaronaught
95

No.

El concepto detrás de las pruebas unitarias se basa en una premisa que se sabe que es falsa desde antes de que se inventaran las pruebas unitarias: la idea de que las pruebas pueden probar que su código es correcto.

Tener muchas pruebas que pasan todas prueba una cosa y solo una cosa: que tienes muchas pruebas que todas pasan. No prueba que lo que las pruebas prueban coincide con la especificación. No prueba que su código esté libre de errores que nunca consideró cuando escribió las pruebas. (¡Y las cosas que pensó probar eran los posibles problemas en los que se estaba enfocando, por lo que es probable que los haya solucionado de todos modos!) Y, por último, pero no menos importante, no prueba que las pruebas, que son código en sí mismas, están libres de errores. (Siga el último hasta su conclusión lógica y terminará con tortugas hasta el final ).

Djikstra destruyó el concepto de pruebas como prueba de corrección en 1988, y lo que escribió sigue siendo igual de válido hoy:

Han pasado dos décadas desde que se señaló que las pruebas del programa pueden demostrar de manera convincente la presencia de errores, pero nunca pueden demostrar su ausencia. Después de citar este comentario bien publicitado devotamente, el ingeniero de software vuelve al orden del día y continúa refinando sus estrategias de prueba, al igual que el alquimista de antaño, que continuó refinando sus purificaciones crioscósmicas.

El otro problema con las pruebas unitarias es que crea un acoplamiento estrecho entre su código y el conjunto de pruebas. Cuando cambie el código, esperaría que aparezcan algunos errores que romperían algunas pruebas. Pero si está cambiando el código porque los requisitos en sí mismos han cambiado, obtendrá muchas pruebas fallidas, y tendrá que revisar manualmente cada una y decidir si la prueba sigue siendo válida o no. (Y también es posible, aunque menos común, que una prueba existente que no sea ​​válida todavía pasará porque olvidó cambiar algo que necesitaba ser cambiado).

Las pruebas unitarias son solo las últimas de una larga línea de modas de desarrollo que prometen facilitar la escritura de código de trabajo sin ser un buen programador. Ninguno de ellos ha logrado cumplir su promesa, y este tampoco. Simplemente no hay un atajo para saber cómo escribir un código de trabajo .

Hay algunos informes de pruebas automatizadas que son realmente útiles en casos donde la estabilidad y la confiabilidad son de suma importancia. Por ejemplo, el proyecto de base de datos SQLite. Pero lo que se necesita para lograr su nivel de confiabilidad es muy poco rentable para la mayoría de los proyectos: una relación de prueba a código SQLite real de casi 1200: 1. La mayoría de los proyectos no pueden permitirse eso, y no lo necesitan de todos modos.

Mason Wheeler
fuente
69
Demuestra que su código se comporta correctamente para esas pruebas. Es un montón de cosas si me preguntas.
Stefano Borini
111
¿Quién cree hoy que las pruebas unitarias son "prueba de corrección"? Nadie debería pensar eso. Tienes razón en que solo prueban que esas pruebas pasan, pero ese es un punto de datos más del que tenías antes de escribir las pruebas unitarias. Necesita probar en muchas capas diferentes para darse una idea de la calidad de su código. Las pruebas unitarias no prueban que su código esté libre de defectos, pero sí aumentan su confianza (o deberían ...) de que el código hace lo que usted diseñó para hacer, y continúa haciendo mañana lo que hace hoy.
Bryan Oakley
40
> but if the test itself is buggy, then you have false confidencey si el probador manual no realiza su trabajo correctamente, también tiene una falsa confianza.
Stefano Borini
33
@MasonWheeler: lo siento, Mason, no estoy convencido. En más de un par de décadas de programación, no creo haber visto personalmente un caso en el que una prueba haya dado una falsa sensación de seguridad. Quizás algunos lo hicieron y los arreglamos, pero de ninguna manera el costo de esas pruebas unitarias superó los enormes beneficios de tenerlos. Si puede escribir código sin probarlo a nivel de unidad, estoy impresionado, pero la gran mayoría de los programadores no pueden hacerlo de manera consistente.
Bryan Oakley
41
Si escribió una prueba de error que aprobó su código, es probable que su código también tenga errores. Las probabilidades de escribir código con errores y una prueba de error son mucho menores que el código con errores solo. Las pruebas unitarias no son una panacea. Son una buena capa adicional (donde es prudente) para reducir la carga de los probadores manuales.
Telastyn
60

Si alguna vez has visto el beneficio de escribir un método principal para probar un pequeño fragmento de código para la escuela, las pruebas unitarias son la versión profesional / empresarial de esa misma práctica.

También imagine la sobrecarga de construir el código, iniciar su servidor web local, navegar a la página en cuestión, ingresar los datos o configurar la entrada a la semilla de prueba adecuada, enviar el formulario y analizar los resultados ... vs construir y golpear el botón de ejecución nUnit.

Aquí hay una imagen divertida también ... ingrese la descripción de la imagen aquí

Encontré esta imagen aquí:
http://www.howtogeek.com/102420/geeks-versus-non-geeks-when-doing-repetitive-tasks-funny-chart/

Heath Lilley
fuente
2
Sí tu puedes. Aísle la capa web en las pruebas unitarias para probar la configuración web (URLS, validación de entrada, etc.). Al agrupar las capas web y de base de datos, puede probar el nivel empresarial sin una base de datos o servidor web. Yo uso dbunit para probar mi DB. Si lo desea, aún puede hacer pruebas de integración completa, pero lo hago como una tarea específica después del desarrollo.
Heath Lilley
12
Lindo gráfico, pero tiene la escala muy mal. Como señalé en mi respuesta, la cobertura de prueba completa de SQLite requiere aproximadamente 1200 veces más código en las pruebas que el código real en el producto en sí. E incluso si usted no es que obsesivo con cobertura total, que aún necesita varias veces más pruebas de que el producto que incluso acercarse a cualquier nivel útil de la cobertura de las pruebas. Para ser precisos aquí, la parte vertical de esa línea roja tendría que seguir subiendo y subiendo y subiendo durante aproximadamente 3 páginas.
Mason Wheeler
27
@MasonWheeler Es un caballo muy bueno al que estás golpeando, aunque creo que puede haber muerto ... SQLite tiene tantas pruebas porque es una maldita base de datos. Quiero asegurarme de que funcione. Como otro ejemplo, el marco Silverstripe tiene una relación de prueba: código cercana a 1: 1, por lo que no es que SQLite sea representativo.
Ve el
15
@MasonWheeler Estás fallando en la primera de las paradojas de Zeno . Si desea escalar esta imagen al nivel de prueba de SQLite, el eje X también tendrá que expandirse aproximadamente 100 veces su longitud actual.
Izkata
2
Esto es especialmente cierto cuando eres un desarrollador de back-end que no tiene tiempo para comenzar a hacer una página web en blanco y negro solo para que puedas probar tu lógica de back-end. Todo lo que tengo que hacer es proporcionar una solicitud simulada y objetos de sesión y ejecutar mis controladores a través de una prueba unitaria, y al final de todo, sé si es correcto o incorrecto. Si usa DI, simplemente inyecte un DAO que interactúa con una base de datos en memoria para que su base de datos no cambie o simplemente arroje un Exceptiony lo atrape para que sus datos no se comprometan. Digo SÍ a las pruebas unitarias.
Varun Achar
49

Las pruebas unitarias tienen algo de mística en estos días. Las personas lo tratan como si el 100% de cobertura de prueba es un santo grial, y como si las pruebas unitarias fueran la única forma verdadera de desarrollar software.

Se están perdiendo el punto.

Las pruebas unitarias no son la respuesta. La prueba es.

Ahora, cada vez que surge esta discusión, alguien (a menudo incluso yo) trotará la cita de Dijkstra: "Las pruebas del programa pueden demostrar la presencia de errores, pero nunca demostrar su ausencia". Dijkstra tiene razón: las pruebas no son suficientes para demostrar que el software funciona según lo previsto. Pero es necesario : en algún nivel, debe ser posible demostrar que el software está haciendo lo que usted quiere.

Muchas personas prueban a mano. Incluso los entusiastas incondicionales de TDD harán pruebas manuales, aunque a veces no lo admitirán. No se puede evitar: justo antes de entrar a la sala de conferencias para demostrar su software a su cliente / jefe / inversores / etc., lo ejecutará a mano para asegurarse de que funcione. No hay nada de malo en eso, y de hecho sería una locura esperar que todo salga bien sin ejecutarlo manualmente, es decir, probarlo , incluso si tiene una cobertura de prueba de unidad del 100% y la máxima confianza en sus pruebas. .

Pero las pruebas manuales, aunque son necesarias para construir software, rara vez son suficientes . ¿Por qué? Porque las pruebas manuales son tediosas, requieren mucho tiempo y son realizadas por humanos. Y los humanos son notoriamente malos para realizar tareas tediosas y que consumen mucho tiempo: evitan realizarlas siempre que sea posible, y a menudo no las hacen bien cuando se ven obligados a hacerlo.

Las máquinas , por otro lado, son excelentes para realizar tareas tediosas y que consumen mucho tiempo. Para eso se inventaron las computadoras, después de todo.

Por lo tanto, las pruebas son cruciales, y las pruebas automatizadas son la única forma sensata de garantizar que sus pruebas se empleen de manera consistente. Y es importante probar y volver a probar a medida que se desarrolla el software. Otra respuesta aquí señala la importancia de las pruebas de regresión . Debido a la complejidad de los sistemas de software, con frecuencia los cambios aparentemente inocuos en una parte del sistema provocan cambios no deseados (es decir, errores) en otras partes del sistema. No puede descubrir estos cambios involuntarios sin alguna forma de prueba. Y si desea tener datos confiables sobre sus pruebas, debe realizarlas de manera sistemática, lo que significa que debe tener algún tipo de sistema de prueba automatizado.

¿Qué tiene que ver todo esto con las pruebas unitarias? Bueno, debido a su naturaleza, las pruebas unitarias son realizadas por la máquina, no por un humano. Por lo tanto, muchas personas tienen la falsa impresión de que las pruebas automatizadas equivalen a pruebas unitarias . Pero eso no es cierto: las pruebas unitarias son solo pruebas automatizadas extra pequeñas .

Ahora, ¿cuál es el valor en pruebas automatizadas extra pequeñas ? La ventaja es que prueban los componentes de un sistema de software de forma aislada , lo que permite una orientación más precisa de las pruebas y ayuda a la depuración . Pero las pruebas unitarias no significan intrínsecamente pruebas de mayor calidad . A menudo conduce a pruebas de mayor calidad, ya que cubre el software con un nivel de detalle más fino. Pero es posible probar completamente el comportamiento de solo un sistema completo, y no sus partes compuestas, y aún probarlo a fondo.

Pero incluso con una cobertura de prueba de unidad del 100%, es posible que un sistema aún no se pruebe a fondo. Debido a que los componentes individuales pueden funcionar perfectamente de forma aislada, aún fallan cuando se usan juntos. Por lo tanto , las pruebas unitarias, si bien son muy útiles, no son suficientes para garantizar que el software funcione como se espera. De hecho, muchos desarrolladores complementan las pruebas unitarias con pruebas de integración automatizadas, pruebas funcionales automatizadas y pruebas manuales.

Si no está viendo el valor en las pruebas unitarias, quizás la mejor manera de comenzar es utilizando un tipo diferente de prueba automatizada. En un entorno web, el uso de una herramienta de prueba de automatización del navegador como Selenium a menudo proporcionará una gran victoria para una inversión relativamente pequeña. Una vez que haya sumergido los dedos de los pies en el agua, podrá ver más fácilmente cuán útiles son las pruebas automatizadas. Y una vez que tiene pruebas automatizadas, las pruebas unitarias tienen mucho más sentido, ya que proporcionan una respuesta más rápida que una gran integración o pruebas de extremo a extremo, ya que puede enfocar las pruebas solo en el componente en el que está trabajando actualmente.

TL; DR: no se preocupe por las pruebas unitarias todavía. Solo preocúpese por probar su software primero.

Daniel Pryden
fuente
Las pruebas unitarias también son escritas por humanos y podrían estar equivocadas.
Seun Osewa
41

Depende

Esta es una respuesta que verá mucho en lo que respecta al desarrollo de software, pero la utilidad de las pruebas unitarias realmente depende de qué tan bien estén escritas. Un número nominal de pruebas unitarias que verifican la funcionalidad de la aplicación para pruebas de regresión puede ser bastante útil; sin embargo, una gran cantidad de pruebas simples que verifican los retornos de las funciones pueden ser bastante inútiles y proporcionar una falsa sensación de seguridad porque la aplicación "tiene muchas pruebas unitarias".

Además, su tiempo como desarrollador es valioso y el tiempo dedicado a escribir pruebas unitarias no es tiempo dedicado a escribir nuevas funciones. De nuevo, esto no quiere decir que no deba escribir pruebas unitarias, pero ¿todas las funciones públicas necesitan una prueba unitaria? Yo diría que la respuesta es no. ¿El código que realiza la validación de entrada del usuario necesita pruebas unitarias? Muy probable ya que es un punto de falla común en las aplicaciones.

Esta es una de esas áreas donde la experiencia entra en juego, con el tiempo reconocerá las partes de la aplicación que podrían beneficiarse de la prueba de la unidad, pero pasará un tiempo antes de llegar a ese punto.

rjzii
fuente
Este es un buen punto. Debe saber cómo escribir buenas pruebas que capturen el valor del SUT.
Andy
3
Básicamente, esto cubre cómo me enseñaron a hacer pruebas unitarias: escribir pruebas para cubrir las situaciones más importantes / rompibles primero, y luego agregar más pruebas cuando sus suposiciones resultaron incorrectas (pensé que algo podría "nunca fallar", pero lo hizo) .
Vuelva a instalar Mónica
38

Los proyectos realizados para las clases universitarias difieren enormemente de las aplicaciones empresariales que escribirás en tu trabajo. La diferencia es la vida útil. ¿Cuánto tiempo "vive" el proyecto universitario? En la mayoría de los casos, comienza cuando escribe la primera línea de código y termina cuando obtiene su marca. Se podría decir que, efectivamente, solo vive el momento de la implementación. "Liberación" suele ser igual a su "muerte".

El software hecho para empresas supera ese punto de lanzamiento del proyecto universitario y continúa viviendo tanto tiempo como las empresas lo necesiten. Lo cual es muy largo . Cuando se habla de dinero, nadie gastará un centavo roto para tener un "código más fresco y ordenado". Si el software escrito en C hace 25 años todavía funciona y es lo suficientemente bueno (como lo entienden las necesidades del propietario de su negocio), espere que se le pida que lo mantenga (agregando nuevas características, mejorando las antiguas, cambiando el código fuente ).

Llegamos a un punto muy importante: la regresión . En el lugar donde trabajo tenemos dos equipos que mantienen dos aplicaciones; uno, escribió alrededor de 5 a 6 años atrás con muy poca cobertura de pruebas de código *, y el segundo, una versión más nueva de la primera aplicación con un completo conjunto de pruebas (unidad, integración y demás). Ambos equipos tienen probadores manuales (humanos) dedicados. ¿Quiere saber cuánto tiempo lleva introducir una característica nueva y bastante básica para el primer equipo? 3 a 4 semanas. La mitad de este tiempo es "verificar si todo lo demás sigue funcionando". Este es un tiempo ocupado para probadores manuales. Suenan los teléfonos, la gente se molesta, algo se rompe de nuevo. El segundo equipo generalmente se ocupa de tales problemas en menos de 3 días.

De ninguna manera digo que las pruebas unitarias hacen que su código sea propenso a errores, correcto u otras palabras elegantes que se le ocurran. Tampoco hacen que los insectos desaparezcan mágicamente. Pero cuando se combinan con otros métodos de pruebas de software automatizadas, hacen que sus aplicaciones sean mucho más fáciles de mantener de lo que hubieran sido de otra manera. Esta es una gran victoria.

Y por último, pero no menos importante, el comentario de Brian, que creo que aclara todo el problema:

(...) aumentan su confianza (o deberían ...) que el código hace lo que usted diseñó para hacer, y continúa haciendo mañana lo que hace hoy.

Porque entre hoy y mañana, alguien podría hacer un pequeño cambio que provocará que el código del generador de informes tan importante se bloquee. Las pruebas aumentan las probabilidades de que descubras esto antes de que tu cliente haga un poco a tu lado.

* Lentamente introducen más y más pruebas en su base de código, pero todos sabemos cómo se ve esto.

km
fuente
10
+1000 para vincular a Software_Regression. Las universidades exponen las pruebas unitarias como algo que debes hacer por pura fe, sin explicar en detalle que hay una enfermedad para prevenir y controlar y que esa enfermedad se llama regresión . (luego está el problema de que las pruebas de regresión son algo muy diferente de las pruebas unitarias, para eso la única lectura que encontré que lo explica bien es la muestra gratuita de este libro )
ZJR
25

¿escribir pruebas unitarias para formularios web ASP.NET es algo que se hace con frecuencia y, en caso afirmativo, cómo resuelvo el problema del "entorno dinámico"?

No se hace a menudo. Trabajar con elementos de la interfaz de usuario no es para lo que son buenas las pruebas unitarias, ya que no hay una excelente manera de verificar mediante programación que las cosas correctas terminen en la pantalla en los lugares correctos.

¿Me aconsejarían que comenzara a escribir pruebas unitarias? Creo que podría ayudarme en la implementación real, pero nuevamente siento que podría retrasarme.

En su caso, sí. Pueden ser muy útiles para verificar casos específicos de manera repetible. Ayudan a actuar como "fricción" contra los cambios problemáticos y como una prueba de fallos cuando se realizan mejores cambios.

Una cosa a tener en cuenta es que generalmente lo retrasarán.

Esto está bien.

Pasar un poco de tiempo ahora (si se hace bien) le ahorrará tiempo en el futuro porque detectan algunos errores, evitan la repetición de algunos errores y le permiten sentirse un poco más cómodo haciendo otras mejoras en el código para evitar que se pudra.

Telastyn
fuente
8
¡+1 por responder el caso de uso de la pregunta! Todos los demás saltaron a la parte de "prueba de unidad" y se olvidaron de la parte de "formularios web ASP.NET" ...
Izkata
1
Esta es una gran respuesta y merece más votos a favor, la razón es porque ha respondido las preguntas y ha sido honesto en su evaluación de ralentizar al desarrollador y no prometer que se detectarán o evitarán todos los errores, lo cual es completamente completamente cierto
Mantorok
11

Me acabo de graduar con un título en CS y actualmente tengo un trabajo como desarrollador junior de .NET (en C # y generalmente en ASP.NET, formularios web, no en ASP.NET MVC). Cuando aún estaba en la universidad, el tema de las pruebas unitarias se cubrió, pero en realidad nunca vi los beneficios.

Eso es porque nunca has programado en grande.

Entiendo lo que se supone que debe hacer, determinar si un bloque de código es adecuado o no, pero nunca he tenido que escribir una prueba unitaria antes. (ni> nunca sentí la necesidad de ...)

Escribir pruebas unitarias obliga a su código a ajustarse a una estructura mental dada que sea comprobable, esté bien documentada y sea confiable. Es mucho más de lo que reclamas.

-He leído que las pruebas unitarias a menudo se realizan escribiendo "simulacros". Si bien entiendo este concepto, parece que no puedo entender cómo se supone que debo escribir simulacros para sitios web que son completamente dinámicos y donde casi todo depende de los datos que provienen de una base de datos.

simula el acceso a la base de datos con una clase simulada que devuelve clases de modelo llenas de datos codificados bien definidos. o , llene una base de datos de prueba con datos de accesorios y trabaje desde allí.

¿Me aconsejarían que comenzara a escribir pruebas unitarias?

Oh sí. Lea primero "Test Driven Development" de Beck .

Creo que podría ayudarme en la implementación real, pero nuevamente siento que podría retrasarme.

Te ralentiza ahora. Pero cuando tenga que depurar durante horas en lugar de días, cambiará de opinión.

cualquier consejo será apreciado :)

Prueba. Créeme. Lamentablemente, también debe ser una política de gestión, pero es algo que ahorra tiempo. Las pruebas permanecen, están allí, ahora y en el futuro. Cuando cambia la plataforma y ejecuta las pruebas, y aún funcionan, sabe que sus cosas funcionan como se esperaba.

Stefano Borini
fuente
8

Editar: por supuesto, me uní al TDD pro / con dogpile y omití la pregunta # 1:

1 - Implementación de pruebas unitarias en formularios web ASP.net:

En primer lugar, si crees que puedes lograr que jueguen con MVC, lucha como un oso de las cavernas rabioso. Como desarrollador front-end / UI, .net MVC es lo que me ayudó a dejar de odiar .net para poder concentrarme mejor en odiar todas las soluciones web de Java con las que me he encontrado. Las pruebas unitarias son problemáticas porque los formularios web realmente difuminan las líneas entre el servidor y el lado del cliente. En cualquier intento de hacer pruebas unitarias, me enfocaría en la manipulación de datos y (con suerte) asumiría que los formularios web manejan la normalización de la entrada del usuario para usted bajo el capó.

2 - Sobre si las pruebas unitarias valen la pena en primer lugar:

Muy bien, divulgación completa:

  • Soy principalmente autodidacta. Mi entrenamiento formal se reduce a un JavaScript, un PHP y una clase de C # y mi propio estudio personal de los principios de OOP y la lectura de cosas como Patrones de diseño.

Sin embargo,

  • Principalmente escribo para la web del lado del cliente y la parte de programación real está en uno de los lenguajes más rápidos y sueltos en lo que respecta a la tipificación dinámica, las funciones de primera clase y la mutabilidad de los objetos.

Eso significa que no escribo para el mismo compilador o máquina virtual. Escribo para 4-20 interpretaciones variables de tres idiomas (sí, dos de ellos meramente declarativos pero también determinan el espacio físico fundamental de la interfaz de usuario con la que estoy trabajando de diferentes maneras a veces) y lo he estado haciendo desde que las interpretaciones fueron un mucho más variados de lo que son hoy. Y no, no soy solo un niño que conecta cosas de JQuery para aplicaciones desechables. Ayudo a construir y mantener cosas bastante sofisticadas con mucha complejidad de elementos de interfaz de usuario.

Entonces, sí, hay muchas oportunidades para algunos ajustes aquí y allá para crear una cascada masiva de fallas si sus habilidades de diseño son una mierda total o si está lanzando desarrolladores mediocres en grandes cantidades a 1-2 problemas de desarrollo de calidad.

Entiendo lo que se supone que TDD debe hacer por usted es que las pruebas realmente tienen que ver con obligarlo a considerar el diseño con más cuidado y mantenerlo enfocado en los requisitos. Es justo, pero el problema aquí es que subvierte lo que deberías estar haciendo, que es diseñar una interfaz, a algo sutil pero fundamentalmente diferente, que es diseñar para probar una interfaz. La diferencia para mí es entre dibujar una imagen clara de que mamá no tendrá que adivinar el significado y llenar toda la página con verde muy rápido para que puedas ser el primer niño en golpear sus lápices de colores en la mesa y gritar "¡listo! " Al cambiar la prioridad a los resultados sobre el proceso y el diseño, básicamente está alentando la implementación continua del código basura, que generalmente es la raíz de sus problemas en primer lugar.

Y luego, por supuesto, existe el "no-el-punto-real", pero a menudo elogiado, el beneficio secundario de las pruebas unitarias mismas que lo ayudan a detectar errores de regresión. Los defensores de TDD tienden a ser un poco dudosos sobre si este es realmente el objetivo o solo un ingenioso efecto secundario, OMI, porque saben muy bien o sospechan al menos que esto simplemente no es suficiente para establecer la ausencia de errores en su código, especialmente en un lenguaje más dinámico como JavaScript, donde asumir que incluso puede predecir cada escenario posible en una larga cadena de dependencias es una locura.

Hay un lugar para las pruebas automáticas en JS, pero un uso mucho mejor de su tiempo que adjuntar una prueba de unidad a cada 'unidad' de su código que entra en contacto con otra es asegurarse de que no tenga un montón de objetos basura que duplican el trabajo o cuyo uso previsto es semánticamente ambiguo allí en primer lugar. Sigues el principio SECO. Resume las cosas para su reutilización / portabilidad cuando el valor de hacerlo se hace evidente (y no un minuto antes). Establece procesos consistentes y formas de hacer las cosas siguiendo más el principio de la zanahoria que el palo (es decir, es demasiado fácil usar sus cosas de la manera correcta para molestarse en querer hacerlo de la manera incorrecta). Y por amor a todas las cosas foo y bar, nunca te entregas a los masivos antipatrones de esquemas de herencia en cascada como un medio de reutilización de código.

Todo lo anterior me ha ayudado a reducir los errores difíciles de diagnosticar en mi código de una manera seria y puede confiar en que es una gran prioridad para alguien que apareció como desarrollador con un conjunto de navegador que no tenía nada mejor que decirle que " uh ha habido un problema con un objeto de tipo 'Objeto' en este número de línea imaginario en un archivo no especificado ". (caramba, gracias IE6) TDD, en mi línea de trabajo, no alentaría estas cosas. Cambiaría el enfoque al 100% de resultados sobre el proceso donde lo que está entre el punto A y B realmente no importa mientras funcione. Es una pérdida de tiempo que se aplicaría mejor para asegurarse de que sus cosas sean legibles, portátiles y fáciles de modificar sin una gran cantidad de roturas confusas en primer lugar.

O tal vez solo estoy siendo demasiado cascarrabias sobre el paradigma en el que estoy arraigado, pero en mi opinión, hacerlo bien en primer lugar es un uso del tiempo mucho más efectivo que cubrir tu trasero para cuando tú o todos los demás en tu El equipo lo hace mal. Y nada debería obligarlo a considerar el diseño en lugar de simplemente implementar las cosas. El diseño debe ser el maldito altar de cada programador. Y todo lo que "lo obligue" a hacer lo correcto o lo proteja de usted mismo debe verse con la misma sospecha reservada para las botellas de aceite de serpiente, IMO. El aceite de serpiente en la TI moderna y el desarrollo general, si aún no lo sabe, se vende por tonelada líquida.

revs Erik Reppen
fuente
1
Escribo muchas pruebas unitarias. No escribiré código sin ellos. Pero estoy de acuerdo con tus sentimientos. Las pruebas deben guiar , no impulsar el desarrollo. No puede automatizar pensar cuidadosamente sobre un problema.
FizzyTea
No tengo ningún problema con las pruebas automatizadas. Pero las adopciones al por mayor en cada coyuntura me parecen más pánico que proceso. Ahorrar ese tiempo para el diseño y automatizar las pruebas y la validación en los puntos en los que es probable que interactúes con una variedad de cosas que no controlas es como lo prefiero.
Erik Reppen
5

En mi experiencia, las pruebas unitarias son realmente muy útiles, cuando comienzas con ellas y te quedas con ellas, es decir, el desarrollo impulsado por pruebas. Este es el por qué:

  • Las pruebas unitarias te obligan a pensar en lo que quieres y cómo verificar que lo obtuviste antes de escribir el código que lo hace . En un escenario TDD, primero escribe la prueba. Por lo tanto, debe saber qué debe hacer el código que está a punto de escribir y cómo puede verificar que lo hizo con éxito, para escribir una prueba "roja" que luego haga "verde" escribiendo el código en Pásalo. En muchos casos, esto le obliga a pensar un poco más sobre el algoritmo que está a punto de escribir para pasar esta prueba, lo que siempre es bueno, ya que reduce los errores lógicos y los "casos de esquina". Mientras que usted está escribiendo la prueba, que está pensando "¿cómo podría esto falla" y "¿qué estoy no probando aquí", lo que conduce a un algoritmo más robusto.

  • Las pruebas unitarias te obligan a pensar cómo se consumirá el código que estás a punto de escribir . Antes de aprender TDD, hubo MUCHAS veces que escribí código esperando que una dependencia funcionara de una manera, y luego recibí una dependencia escrita por un colega que funcionó de una manera completamente diferente. Si bien esto aún es posible con TDD, la prueba unitaria que está escribiendo lo obliga a pensar en cómo desea usar el objeto que está escribiendo, porque es un ejemplo de uso de dicho objeto. Entonces, con suerte, escribirá el objeto de tal manera que sea fácil de consumir y, por lo tanto, adaptar si es necesario (aunque la programación a interfaces predefinidas es una mejor solución general para este problema que no requiere TDD).

  • Las pruebas unitarias le permiten "codificar mediante pruebas" . Una herramienta de refactorización como ReSharper puede ser tu mejor amigo si lo dejas. Puede usarlo para definir el esqueleto de la nueva funcionalidad a medida que define el uso en una prueba.

    Por ejemplo, supongamos que necesita crear un nuevo objeto MyClass. Comienza creando una instancia de MyClass. "¡Pero MyClass no existe!", Se queja ReSharper. "Entonces créalo" dices, presionando Alt + Enter. Y listo, tienes tu definición de clase. En la siguiente línea de código de prueba, llama a un método MyMethod. "¡Pero eso no existe!", Dice ReSharper. "Entonces créalo", repites, con otro Alt + Enter. Con algunas pulsaciones de teclas, ha definido el "esqueleto" de su nuevo código. A medida que continúe desarrollando el uso, el IDE le dirá cuándo algo no encaja y, por lo general, la solución es lo suficientemente simple como para que el IDE o una herramienta que lo conecta sepa cómo solucionarlo.

    Ejemplos más extremos se ajustan al modelo "Triple-A"; "Organizar, actuar, afirmar". Configure todo, realice la lógica real que está probando, luego afirme que la lógica es correcta. Codificando de esta manera, es muy natural codificar la solución en la prueba; luego, con unas pocas pulsaciones de teclas, puede extraer esa lógica y colocarla en algún lugar donde pueda usarse en el código de producción, luego hacer pequeños cambios en la prueba que la apunten a la nueva ubicación de la lógica. Hacerlo de esta manera te obliga a diseñar el código de forma modular y fácil de reutilizar porque las unidades que estás probando aún deben estar accesibles.

  • Las pruebas unitarias se ejecutan muchos órdenes de magnitud más rápido que cualquier prueba manual que se te ocurra. Hay un punto que se cumple muy rápidamente en el caso de proyectos más grandes, en el que el tiempo de sobrecarga de las pruebas unitarias comienza a pagarse por sí solo al reducir el tiempo dedicado a las pruebas manuales. SIEMPRE debe ejecutar el código que acaba de escribir. Tradicionalmente, lo hacía manualmente, iniciando un gran programa, navegando a través de la interfaz de usuario para configurar la situación para la que cambió el comportamiento y luego verificando los resultados nuevamente a través de la interfaz de usuario, o en la forma de datos producidos. Si el código fuera TDDed, simplemente ejecuta las pruebas unitarias. Le garantizo que si está escribiendo buenas pruebas unitarias, la última opción será muchas veces más rápida que la anterior.

  • Las pruebas unitarias atrapan la regresión . Nuevamente, hubo muchas veces antes de que aprendiera TDD donde ingresé, hice lo que pensé que era un cambio quirúrgico en un código, verifiqué que el cambio solucionó un comportamiento errante (o produjo un nuevo comportamiento deseado) en la situación informada , y lo revisó para su lanzamiento, solo para descubrir que el cambio rompió algún otro caso de esquina en un módulo completamente diferente que reutilizó ese mismo bloque de código. En un proyecto TDDed, puedo escribir una prueba verificando un cambio que estoy a punto de hacer, hacer el cambio, luego ejecutar el conjunto completo, y si todos los demás usos del código fueron TDDed y mi cambio rompió algo, las pruebas para esos otras cosas fallarán, y puedo investigar.

    Si los desarrolladores tuvieran que buscar y probar manualmente todas las líneas de código que podrían verse afectadas por un cambio potencial, nunca se haría nada porque el costo de determinar el impacto de un cambio haría que el cambio no fuera factible. Como mínimo, nada sería SÓLIDO y, por lo tanto, fácil de mantener, porque nunca te atreverías a tocar algo que pueda usarse en varios lugares; en su lugar, lanzaría su propia solución de cambio muy similar pero que incorpora su cambio menor para este caso, violando SRP y probablemente OCP, y convirtiendo lentamente su base de código en una colcha de retazos.

  • Las pruebas unitarias modelan la arquitectura de una manera típicamente ventajosa . Las pruebas unitarias son pruebas realizadas de forma aislada de cualquier otra lógica. Para poder probar el código de la unidad, debe escribir el código de tal manera que puedaaislarlo. Las buenas decisiones de diseño, como el acoplamiento flojo y la inyección de dependencia, naturalmente se sacuden del proceso TDD; las dependencias deben inyectarse para que en una prueba pueda inyectar un "simulacro" o "trozo" que produce la entrada o maneja la salida para la situación que se está probando sin crear "efectos secundarios". La mentalidad de "uso primero" de TDD generalmente conduce a la "codificación de interfaces", la esencia del acoplamiento flexible. Estos buenos principios de diseño le permiten realizar cambios en la producción, como reemplazar una clase completa, sin requerir que se cambien grandes masas de la base de código para adaptarse.

  • Las pruebas unitarias muestran que el código funciona, en lugar de probar que funciona . A primera vista, puede pensar que es una desventaja; ¿seguramente la prueba es mejor que la demostración? La teoría es genial; La teoría computacional y algorítmica es la base de nuestro trabajo. Pero, una prueba matemática de la corrección de un algoritmo no es prueba de la corrección de la implementación . Una prueba matemática solo muestra que el código que se adhiere al algoritmo debe ser correcto. Una prueba unitaria muestra que el código realmente escrito hace lo que usted pensó que haría, y por lo tanto es evidencia de que es correcto. En general, esto es mucho más valioso que una prueba teórica.

Ahora, dicho todo esto, hay desventajas en las pruebas unitarias:

  • No puedes probar todo unitario. Puede diseñar su sistema para minimizar el número de LOC no cubiertos por una prueba unitaria, pero simplemente habrá ciertas áreas del sistema que no pueden ser probadas por unidad. Su capa de acceso a datos se puede burlar cuando la usa otro código, pero la capa de acceso a datos en sí contiene muchos efectos secundarios y, por lo general, no es factible realizar pruebas unitarias (¿la mayoría?) De un Repositorio o DAO. Del mismo modo, el código que usa archivos, establece conexiones de red, etc. tiene efectos secundarios incorporados y simplemente no puede probar la línea de código que lo hace. Los elementos de la interfaz de usuario a menudo no se pueden probar por unidad; puede probar métodos de código subyacente, como controladores de eventos, puede probar constructores de unidades y verificar que los controladores estén conectados, pero simplemente no hay sustituto en el código para que un usuario haga clic con el mouse en un elemento gráfico en particular y vea cómo se llama al controlador. Alcanzar estos límites entre lo que puede y no puede probarse adecuadamente en la unidad se llama "raspar el borde de la caja de arena"; más allá de ese punto, está limitado a usar pruebas de integración, pruebas de aceptación automatizadas y pruebas manuales para verificar el comportamiento.

  • Muchas ventajas de las pruebas unitarias no se aplican sin TDD. Es perfectamente posible escribir código, luego escribir pruebas que ejerciten el código. Todavía son "pruebas unitarias", sin embargo, al escribir el código primero, pierde muchas de las ventajas inherentes al desarrollo "prueba primero": el código no está necesariamente diseñado de una manera que pueda probarse fácilmente, o incluso usarse en la producción ; no obtienes el proceso de pensamiento de "doble verificación" inherente a escribir la prueba y pensar en lo que no habías estado pensando; no codificas probando; y si escribe código, pruébelo manualmente y vea que funciona, luego codifique una prueba unitaria que falla, ¿cuál es el error, el código o la prueba? Sus principales ventajas son la prevención de regresión (recibirá una alerta cuando el código que anteriormente pasó sus pruebas ahora falla) y la verificación de alta velocidad en comparación con las pruebas manuales. La pérdida de TDD '

  • Las pruebas unitarias introducen una sobrecarga . Simplemente, está escribiendo código para probar el código que está escribiendo. Esto necesariamente aumentará el LOC total de un proyecto de desarrollo, y sí, el LOC para las pruebas puede exceder el LOC para el proyecto real. Los desarrolladores ingenuos y los no desarrolladores verán este estado de cosas y dirán que las pruebas son una pérdida de tiempo.

  • Las pruebas unitarias requieren disciplina. Debe escribir pruebas que ejerciten adecuadamente la base de código (buena cobertura de código), debe ejecutarlas regularmente (ya que cada vez que comete un cambio, se debe ejecutar el conjunto completo) y debe mantener todo "verde" ( todas las pruebas pasan). Cuando las cosas se rompen, debe corregirlas arreglando el código que no cumple con las expectativas o actualizando las expectativas de las pruebas. Si cambia las pruebas, debe preguntarse "por qué" y vigilar muy de cerca a usted mismo; es increíblemente tentador simplemente cambiar las afirmaciones fallidas para que coincidan con el comportamiento actual, o simplemente eliminar las pruebas fallidas; pero, esas pruebas deben basarse en los requisitos, y cuando las dos no coinciden, tiene un problema. Si estas cosas no se hacen,

  • Las pruebas unitarias requieren más equipo. La solución habitual a la necesidad anterior de disciplina y una tendencia natural de los humanos a ser flojos y compactos, es un "build-bot" que ejecuta un paquete de software de "Integración continua" como TeamCity, CruiseControl, etc., que realiza pruebas unitarias, calcula codifica las métricas de cobertura y tiene otros controles como "triple-C" (cumplimiento de la convención de codificación, a la FxCop). El hardware del build-bot debe tener un rendimiento razonable (de lo contrario, no se mantendrá al día con la tasa de registros de código que realizará el equipo promedio), y los procedimientos de registro en el bot deben mantenerse actualizados (si se crea una nueva biblioteca de pruebas unitarias, los scripts de compilación que ejecutan pruebas unitarias deben cambiarse para buscar en esa biblioteca). Esto es menos trabajo de lo que parece, pero generalmente requiere cierta experiencia técnica por parte de al menos unas pocas personas en el equipo que saben cómo funcionan los detalles de varios procesos de construcción (y por lo tanto pueden automatizarlos en scripts y mantener dichos scripts). También requiere disciplina en la forma de prestar atención cuando la compilación "se rompe", y arreglar lo que causó que la compilación se rompa (correctamente) antes de registrar algo nuevo.

  • Las pruebas unitarias pueden obligar a que el código sea diseñado de una manera no ideal . Si bien TDD suele ser bueno para la modularidad y la reutilización del código, puede ser perjudicial para la accesibilidad adecuada del código. Los objetos y miembros, ubicados en bibliotecas de producción, no pueden ser privados o internos si se usan directamente en pruebas unitarias. Esto puede causar problemas cuando otros codificadores, que ahora ven un objeto, intentan usarlo cuando deberían usar otra cosa presente en la biblioteca. Las revisiones de código pueden ayudar con esto, pero pueden ser una preocupación.

  • Las pruebas unitarias generalmente prohíben los estilos de codificación de "desarrollo rápido de aplicaciones". Si está escribiendo pruebas unitarias, no está codificando "rápido y suelto". Por lo general, eso es algo bueno, pero cuando está bajo una fecha límite impuesta desde fuera de su control, o está implementando un cambio de alcance muy pequeño y la parte interesada (o su jefe) se pregunta por qué tiene que suceder todo este problema solo para Si cambia una línea de código, puede ser simplemente imposible escribir y mantener el conjunto de pruebas de unidad adecuado. Los procesos ágiles generalmente ayudan con esto al permitir que los desarrolladores puedan opinar sobre los requisitos de tiempo; recuerde, todo lo que el vendedor tiene que hacer es decir "sí, podemos" y reciben el cheque de la comisión, a menos que el proceso involucre a las personas que realmente tienen que hacer el trabajo diciendo "no, no podemos" y que se les preste atención. Pero, no todos son ágiles, y Agile tiene sus propias limitaciones.

KeithS
fuente
4

Las pruebas unitarias son útiles cuando se usan correctamente; Hay varios problemas con su lógica.

"Cuando estoy desarrollando paso por muchas pruebas y errores", dijo Kevin.

Mira la programación por coincidencia. Es mejor entender lo que debe hacer un código y luego demostrar que lo hace a través de una prueba unitaria. ¡No asuma que un código funciona simplemente porque la IU no se rompió cuando ejecutó el programa!

s writing unit tests for ASP.NET web forms something that is done often

No conozco datos estadísticos que indiquen con qué frecuencia las personas prueban los formularios web. No importa. La interfaz de usuario es difícil de probar y las pruebas unitarias tampoco deben estar acopladas a una interfaz de usuario. Separe su lógica en capas, bibliotecas de clases que se pueden probar. Pruebe la IU por separado de la lógica de fondo.

So, question number 2: Would you guys advise me to start writing unit tests?

Si. Una vez que te acostumbras a ellos, te aceleran. El mantenimiento lleva mucho más tiempo y es más costoso que la fase de desarrollo inicial. El mantenimiento es de gran ayuda con las pruebas unitarias, incluso con las pruebas iniciales y la reparación de errores.

revs P.Brian.Mackey
fuente
Existen marcos de prueba que pueden hacer pruebas en páginas aspx para simplemente probar si las páginas se cargan con éxito o no en diferentes escenarios. Puede que esto no sea lo suficientemente bueno, pero es mejor que nada.
asombro
4

En un nivel práctico, las pruebas unitarias pueden ser extremadamente útiles por una razón muy importante: puede probar un código a la vez.

Cuando está escribiendo una secuencia completa de pasos complejos y los depura al final, tiende a encontrar muchos errores, y el proceso generalmente es más difícil porque está más avanzado en el proceso. En Visual Studio, puede generar una prueba rápida, cambiarla un poco y ejecutar SOLAMENTE esa prueba . Entonces sabe que, por ejemplo, un método que lo llama puede confiar en él. Entonces aumenta la confianza.

¡Las pruebas unitarias no prueban que su programa sea correcto! : Las pruebas unitarias verifican las regresiones en el código sensible y le permiten probar nuevos métodos que escriba.

Las pruebas unitarias no están destinadas a probar los front-end : piense en una prueba unitaria como ese pequeño proyecto que crea para probar un nuevo método que está escribiendo o algo así, no como una especie de condición que su código debe cumplir.

Las pruebas unitarias funcionan muy bien para entornos colaborativos : si tengo que proporcionar un método a un colega que está usando una tecnología completamente diferente a la mía, como por ejemplo, lo está llamando desde iOS, entonces puedo escribir rápidamente una prueba unitaria para ver si método que desea a) Vuelve a ejecutar los datos correctos b) Realiza según sus especificaciones c) No tiene cuellos de botella desagradables.

Tjaart
fuente
"Las pruebas unitarias no están destinadas a probar los frontales" ¿Quién dice eso? No lo estoy cuestionando. Solo me gustaría saberlo porque mucha gente parece tener una idea equivocada y me gustaría ayudarlos con el palo que dice TDD-advocate-source.
Erik Reppen
Algunas personas, incluyéndome a mí, tuvieron esa idea errónea cuando se encontraron por primera vez con las pruebas unitarias, por lo que estoy aclarando eso. No sé por qué sientes que te estoy desafiando, de hecho, estoy totalmente de acuerdo contigo.
Tjaart
4

Una cosa que no parece mencionarse es la complejidad de probar diferentes tipos de código.

Cuando se trata de cosas con entradas y salidas simples, generalmente es fácil realizar pruebas unitarias y si las pruebas se eligen teniendo en cuenta los casos extremos del código que se está probando, le darán mucha confianza de que son correctas. No escribir pruebas para dicho código sería una locura. (Tenga en cuenta que la mayoría del código que entra en las bibliotecas cumple con este criterio).

Sin embargo, en otros casos terminas teniendo que construir simulacros enormes para probar porque el código está jugando con datos subyacentes complejos (generalmente una base de datos pero no tiene que serlo) o produce datos de salida muy complejos (piensa en una rutina que se convierte un valor inicial en un nivel de juego para un ejemplo bastante extremo) y las pruebas unitarias no son tan útiles. Cubrir todo en sus casos de prueba generalmente es un sueño imposible y cuando encuentra un error, casi siempre es un caso en el que nunca pensó y, por lo tanto, no podría haber construido una prueba de todos modos.

No hay balas de plata, cualquier cosa retratada como una bala de plata no es tan buena como afirman sus defensores, pero eso no significa que sea inútil.

Loren Pechtel
fuente
4

Escribir pruebas unitarias para la aplicación de formularios web ASP.NET NO es común y es muy difícil de lograr. Sin embargo, no significa que el proyecto deba omitirlo.

Las pruebas unitarias son corner stonesaplicaciones de misión crítica y brindan confiabilidad y tranquilidad de que la funcionalidad principal funciona como se espera.

En realidad, puede introducir pruebas unitarias mucho más fácilmente con un patrón ASP.NET MVP que podría usarse en el desarrollo de formularios web. Introducirá la separación de preocupaciones y ability to write essential unit tests.

Algunas referencias que pueden ser útiles para buscar son:

revs ElYusubov
fuente
2
+1 No importa si estás haciendo pruebas unitarias o no, MVP es el camino a seguir cuando trabajas con Web Forms (tal vez WinForms también).
simoraman
3

El propósito de las pruebas unitarias es permitirle cambiar de manera segura su código (refactorización, mejora, etc.) sin temor a que pueda romper algo dentro del sistema. Esto resulta muy útil para aplicaciones grandes, cuando realmente no conoce todos los efectos de su cambio de código (a pesar del acoplamiento flojo).

m3th0dman
fuente
66
Sin miedo es una falsa sensación de seguridad.
Codificador
Quizás "menos miedo" es una frase mejor, pero la respuesta sigue siendo en gran medida correcta.
Vuelva a instalar Mónica
1
@Coder Si sus pruebas pasan después de la refactorización, puede estar bastante seguro de que su mejora en el código no cambió la forma en que se comporta la aplicación (en términos generales, no introdujo ningún error nuevo, pero esto no es necesariamente cierto porque no puede lograrlo 100% de cobertura de prueba).
m3th0dman
2

Según mi experiencia , , las pruebas unitarias son útiles.

Unit Testing se trata de segregar partes del código que usted escribe y garantizar que funcionen de forma aislada. De hecho, este aislamiento puede implicar la creación de objetos falsos o simulados para hablar con el objeto que está probando, o puede que no. Depende mucho de la arquitectura de su objeto.

Las pruebas unitarias otorgan varios beneficios:

Principalmente, esto asegura que las unidades que pruebe funcionen como usted, el desarrollador, cree que deberían funcionar. Si bien esto es menos de lo que parece: no necesariamente dice que el objeto funciona correctamente; solo que funciona como crees que debería funcionar, es una afirmación mucho más sólida que el método de prueba y error que es necesario sin pruebas unitarias.

Además, garantiza que las unidades continúen funcionando de la forma en que usted, el desarrollador, pensó que deberían funcionar. El software cambia, y esto puede afectar a las unidades de manera inesperada.

Otro efecto secundario es que significa que las unidades se prueba hacer el trabajo de manera aislada. Esto generalmente significa que comienza a programar en interfaces en lugar de clases concretas, reduciendo el acoplamiento y aumentando la cohesión: todas las características comunes de un buen diseño. Sí: simplemente permitir que sus unidades de código tengan pruebas unitarias mejorará naturalmente el diseño de su código.

Sin embargo...

Las pruebas unitarias no son el final de las pruebas. Todavía se requieren otros tipos de pruebas. Por ejemplo, incluso cuando ha demostrado que las unidades funcionan de la forma en que espera que funcionen, aún debe demostrar que cada unidad funciona de la manera en que las unidades que le hablan esperan que funcione. Es decir, ¿sus componentes se integran entre sí correctamente?

Kaz Dragon
fuente
1

Para aplicaciones simples con un pequeño número de capas para probar (Ventana principal -> submenú), tal vez compilar para ejecutar para verificar los cambios está bien.

Para aplicaciones más grandes donde se necesita una navegación de 30 segundos para acceder a la página que está probando, esto termina siendo muy costoso.

Día de defenestración
fuente
1

Quiero agregar un lado nuevo (en realidad, uno bastante viejo) a esto: las pruebas unitarias no son tan útiles si su código está bien diseñado .

Sé que la mayoría de los programadores ya no hacen el diseño del programa, todavía lo hago, y descubrí que las pruebas unitarias son una necesidad que requiere mucho tiempo para adaptarse a una cultura TDD, pero hasta ahora, he conocido solo 1-2 menores errores por miles de líneas de pruebas de mi código, no solo lo que escribí, sino también lo que escribieron los probadores oficiales.

Supongo que ya no harás el diseño del programa, la gente actual te presionará para que no lo hagas, pero quizás valga la pena recordar que la prueba unitaria es un método de muy, muy baja eficiencia en comparación con el diseño.

Este es un argumento dijsktraian: la prueba unitaria solo se puede ejecutar contra un programa que esté lo suficientemente detallado como para ejecutarse.

Si dibuja diagramas de flujo / diagramas de estado / acción, diagramas de secuencia, inventarios de objetos (y por último Y menos, diagramas de clase) para su código antes de escribirlo, podrá eliminar la mayoría de los errores potencialmente amenazantes simplemente rastreando sus líneas y verificando sus nombres.

Hoy en día, los diagramas de clase se generan a partir del código, que contiene cientos, a veces miles de clases y son completamente inutilizables; cualquier cosa que contenga más de 15 elementos está más allá del reconocimiento humano.

Debe saber qué clases 10 + -5 importan o qué hace en este momento, y poder verificar su código desde múltiples puntos de vista, cada diagrama representa EXACTAMENTE los puntos de vista que está mirando, y eliminará miles de errores en papel.

  • Al registrar un código dinámico si se cumplen los tipos (con solo mostrar los tipos de entrada / salida en un diagrama de flujo y conectarlos con un lápiz o un color diferente),
  • verificar si se manejan todos los estados (verificando la totalidad de sus condiciones),
  • rastrear las líneas para asegurarse de que todo llegue a su fin (cada diagrama de flujo debe ser un autómata determinista de estado finito completamente definido, para personas con mentalidad matemática
  • Asegurarse de que ciertos componentes no tienen nada que ver entre sí (mediante la extracción de todas sus dependencias) (bueno para la seguridad)
  • simplificando el código convirtiendo las dependencias en asociaciones (las dependencias provienen de qué clases usan los métodos miembros)
  • comprobar nombres, buscar prefijos comunes, borrar sinónimos, etc.

hay mucho más fácil ...

Además, descubrí que mis aplicaciones son más utilizables, si provienen directamente de casos de uso ... si los casos de uso están bien escritos (sujeto del verbo ACTOR, el mantenedor solicita abrir el cajero automático) ... Eso

He codificado con más del 95% de las coberturas de código. Por supuesto, a veces hago pruebas unitarias, especialmente. para verificaciones de límites en los cálculos, pero todavía tengo que encontrar regresiones serias (grave: no desaparece en 24 horas) por no usar pruebas unitarias, incluso para refactorizaciones.

A veces no hago una sola línea de código durante 3-4 días seguidos, solo dibujo. Luego, en un día, escribo 1500-2000 líneas. Al día siguiente, en su mayoría están listos para la producción. A veces se escriben pruebas unitarias (con más del 80% de cobertura), a veces (además) se les pide a los evaluadores que intenten romperlo, cada vez, a algunas personas se les pide que lo revisen al mirarlo.

Todavía tengo que ver que esas pruebas unitarias encuentren algo.

Desearía que el diseño pensara en lugar de TDD ... pero TDD es mucho más fácil, es como ir con un mazo ... el diseño necesita pensar, y la mayor parte del tiempo estás fuera del teclado.

Aadaam
fuente
Creo que puedes diseñar en el teclado. Pero planificar y organizar el código requiere mucho más pensamiento que simplemente tropezar con la entrada a la salida en clases que también podrían ser funciones monolíticas.
Erik Reppen
Confía en mí, las funciones monolíticas no se ajustan a un papel A4 (o carta de EE. UU.). A veces, cuando soy flojo, hago "diseño" en el teclado, pero esa no es la misma calidad. Cada vez que hago un desarrollo serio, diseño con UML. Cuando estás dibujando estos, estás tratando de explicarte a ti mismo y a los demás de una manera muy restringida pero estructurada lo que está sucediendo, y cuando eres capaz de explicar el código desde todas las perspectivas, solo entonces escribes en, y de repente todos sus errores están en la mayoría de los errores de tipeo ...
Aadaam