2009-06-30 10 views
22

En Proggit hoy estaba leyendo el hilo de comentarios en una presentación titulada, "Why Unit Testing Is A Waste of Time".¿Qué debería ser una "unidad" cuando se realiza una prueba unitaria?

No estoy realmente preocupado con la premisa del artículo tanto como yo con un comment hecho relativo a que:

El tallo del problema es que la mayoría de las “unidades” de código en software de negocios proyectos son triviales.

¿Cambia el tamaño de la unidad hasta que ya no sea trivial? ¿Quién demonios definió la unidad de código como una sola función método o método de todos modos?

y

Bueno, algunos de los chicos con los que trabajé querían definir una unidad tan solo funciones. Fue completamente estúpido. Mi definición favorita de "unidad" es: la pieza más pequeña del código que puede ser probada de manera útil.

¿Pasamos demasiado tiempo solo para simular algunos objetos y probar un código trivial y no agregar realmente nada de valor?

¿Qué debe ser una "unidad" cuando se prueban las unidades? ¿Las pruebas de nivel de función son demasiado granulares?

+0

Esta pregunta es diferente, pero posiblemente relacionada con http://stackoverflow.com/questions/517977/what-do-you-test-with-your-unit-tests y http://stackoverflow.com/questions/962821/how-much-should-each-unit-test-test –

+0

@Thomas Owens, gracias por los enlaces. – mmcdole

+0

No hay problema. Soy fanático de que todos tengan toda la información que necesitan, y la odio cuando falta información faltante. –

Respuesta

14

Puede parecer trivial citar Wikipedia, pero creo que es muy breve y preciso en este caso:

Una unidad es la parte más pequeña comprobable de una aplicación.

Esto parece estar de acuerdo con el comentario en su pregunta de que una unidad es "la pieza más pequeña del código que puede ser probada útilmente". En otras palabras, haga que la unidad sea lo más pequeña posible de manera que tenga sentido para el desarrollador/comprobador solo.

A menudo querrá probar partes de un proyecto de forma aislada, y luego probar cómo interactúan en combinación. Tener varios niveles (niveles) de pruebas unitarias suele ser una buena idea, ya que ayuda a garantizar que el código funcione como debería en todos los niveles, desde las funciones individuales hasta las tareas independientes completas. Personalmente, no creo que sea incorrecto, o incluso inútil, poner a prueba funciones individuales, siempre y cuando estén haciendo algo útil en sí mismas, lo que a menudo puede ser el caso.

Para ser honesto, no hay una definición definida o rigurosa de una "unidad" en "pruebas unitarias", que es precisamente por qué se usa el vago término "unidad". Aprender lo que se debe probar y en qué nivel es una cuestión de experiencia y, a menudo, simplemente prueba y error. Puede sonar como una respuesta ligeramente insatisfactoria, pero creo que es una regla sólida a seguir.

+0

@Noldorin: <- Sabiduría en su máxima expresión :) - Casi todo lo que tomo de Wikipedia es con al menos una unidad de sal. Entonces, si un 'grano' funciona, qué tal un pellizco ... ahora una cucharada. - Sin embargo, al igual que la sal en una receta, si la unidad es demasiado grande, entonces la prueba misma se vuelve autoritaria. – IAbstract

3

Yo diría que una unidad es la parte más pequeña significativa del trabajo que se puede separar de otros pasos en el pseudocódigo.

Por ejemplo, si usted está tratando de hacer una serie de pasos para procesar algunos datos, como

  1. escanear el conjunto de datos para los valores mínimo, máximo, mediana, media
  2. generar un histograma
  3. generar una función de reasignación
  4. reasignación de los datos de salida
  5. los datos

Cada uno de esos pasos sería una 'unidad', y toda la serie es también en sí misma una 'unidad' (para probar que la cohesión entre cada uno está funcionando). Cualquiera de estos pasos podría ser de cuatro funciones (para el primer paso, si el programador está ejecutando cuatro bucles), o una función, o lo que sea, pero al final, las entradas conocidas deberían dar salidas conocidas.

3

Nada es trivial, si se tiene en cuenta la Ley de Murphy.

Bromas aparte y asumiendo un entorno OO, me acerco a Pruebas unitarias tomando una clase como unidad, porque a menudo los diversos métodos modifican el estado interno y quiero estar seguro de que el estado entre varios métodos es constante.

Desafortunadamente, a menudo la única manera de comprobar la coherencia es invocar varios métodos de una clase para ver si fallan o no.

4

Siempre he probado en el nivel de función, y funcionó bien. El gran punto para mí es que las pruebas unitarias prueban el contrato entre dos piezas de código. La prueba unitaria solo actúa como llamante y garantiza que el código que se está probando (sin importar cuán grande sea (una única función o una gran biblioteca anidada que demuestre 30 minutos para probar) devuelve los resultados de una manera predecible.

El objetivo de una unidad es probarlo para garantizar la compatibilidad (al no interrumpir las interacciones) y garantizar resultados predecibles. Las pruebas en cualquier lugar donde haya un intercambio de información ayudarán a estabilizar su aplicación.

ACTUALIZACIÓN: También siempre he añadido una prueba unitaria cada vez que un cliente o usuario informa un caso extremo que interrumpe una interacción en mi aplicación. Repararlo no es suficiente para mí: agregar una prueba unitaria para garantizar que la corrección retenga la regresión y ayuda a mantener las cosas estables en la línea.

+0

Si está depurando un contenedor, ¿cuál es el sentido de probarlo de forma individual, buscarlo y reducirlo? Una prueba seria debería involucrarlos a todos en una sola función de prueba. – akappa

+0

No estoy seguro de entender lo que me está preguntando, pero como de costumbre, depende que si un solo "Este contenedor actúa como espero" usando algunos datos de prueba está bien, entonces combínelos en una sola prueba. Si desea ver la funcionalidad desglosada, divídala en varias pruebas. También vale la pena mencionar que las pruebas unitarias (para mí, al menos) sirven como punto de prueba: si quiero forzar a una aplicación a portarse mal, puedo modificar mi prueba ligeramente, en lugar de tener que dividir un objeto en el contexto de una mayor aplicación, puedo probar un solo objeto o característica de un objeto, según mis pruebas. – SqlRyan

+1

@appaka: El sentido es que, si su implementación de 'put' se rompe, solo fallará su prueba' put'. Mientras que si tuviera una sola prueba, todo lo que sabría es "algo está roto en cualquiera de las operaciones individuales' put', 'fetch', o' reduce', o tal vez en alguna combinación de ellas usadas juntas ". Pasar de esa información, a "poner" se rompe, "es mucho trabajo extra y hace que las pruebas de tu unidad sean mucho menos útiles. – Domenic

1

En general, cuanto más pequeñas puedan hacer sus unidades, más útiles y efectivas serán sus pruebas unitarias. El objetivo de las pruebas de unidades es poder localizar cualquier error recientemente introducido en una pequeña parte del código.

1

Para mí, una "unidad" es cualquier comportamiento significativo de una clase que, en 8-12 meses en el camino, no voy a recordar.

Y con pruebas de unidad bien escritas (piense en BDD), no tendré que hacerlo, porque mi prueba me describirá y verificará el código en inglés sencillo.

0

¿Cambiar el tamaño de la unidad hasta que ya no sea trivial? ¿Quién demonios definió la unidad de código como una sola función método o método de todos modos?

Si es demasiado difícil probar una "unidad" definida como método, entonces es probable que el método sea demasiado grande o complicado para crear una prueba unitaria.

Sigo una metodología similar sugerida por rwmnau, y la prueba en el nivel de método. Además de crear una prueba por método, creo pruebas adicionales para las diferentes rutas de código en cada método. A veces, hacer hincapié en todas las rutas de código puede ser complicado. Mi desafío es tratar de evitar escribir los tipos de métodos a menos que no haya una mejor solución en términos de rendimiento y complejidad del código.

También utilizo simulacros para probar contratos entre componentes.

4

Una "unidad" debe ser una sola unidad atómica para su definición. Es decir, precisamente lo que define una "unidad" para las pruebas unitarias es más bien subjetiva; puede depender bastante de lo que sea su arquitectura, y de cómo su aplicación elija descomponer las unidades funcionales. Lo que estoy diciendo es que no hay una "unidad" claramente definida, excepto por lo que definas. Una "unidad" puede ser un único método que tiene un único efecto secundario, o puede ser un conjunto relacionado de métodos que, en conjunto, definen un único conjunto coherente de funcionalidades.

La racionalidad es bastante importante aquí; es completamente posible escribir pruebas unitarias para cada acceso de cada clase que tenga; sin embargo, eso es claramente excesivo. Del mismo modo, es posible pero tonto definir toda su aplicación como una unidad y esperar tener una prueba única para probarla.

En general, desea una "unidad" para las pruebas para describir un trozo de funcionalidad claramente definido y claramente distinto. En cada nivel de visualización de su aplicación, debería poder ver claros "átomos" de funcionalidad (si su diseño es bueno); estos pueden ser tan simples como "recuperar un registro de la base de datos" para una vista de bajo nivel y tan complicados como "crear, editar y eliminar un usuario" en una vista de alto nivel. Tampoco son mutuamente excluyentes; puede tener fácilmente ambos como pruebas unitarias.

El punto que se debe tomar aquí es que la unidad que desea probar es la unidad que tiene sentido. Desea que las pruebas unitarias validen y verifiquen la funcionalidad; entonces, lo que una unidad prueba es lo que define como funcionalidad. ¿Qué es una unidad de funcionalidad? Eso depende de tu situación individual para definir.

1

Sospecho que "pruebas unitarias" es un término mal utilizado. Hoy en día, el término no solo se usa para referirse a probar un pequeño fragmento de código, sino que se usa para cualquier prueba que sea automática.

Tiendo a escribir mis pruebas antes de escribir mi código, por lo que no puedo decir cuándo lo escribo por primera vez si va a causar la creación de algunas líneas nuevas, un nuevo método o una nueva clase.

Entonces, en una palabra: mu.

Cuestiones relacionadas