¿Hay algún valor en escribir una prueba unitaria que sea un subconjunto de otra prueba?

15

Para dar un ejemplo ligeramente artificial, digamos que quiero probar que una función devuelve dos números y que el primero es más pequeño que el segundo:

def test_length():
    result = my_function()
    assert len(result) == 2

def test_order()
    a, b = my_function()
    assert a < b

Aquí, si test_lengthfalla, test_ordertambién fallará. ¿Es una buena práctica escribir test_lengthu omitirlo?

EDITAR: tenga en cuenta que en esta situación, ambas pruebas son en su mayoría independientes entre sí, cada una se puede ejecutar de forma aislada, o se pueden ejecutar en orden inverso, esto no importa. Entonces ninguna de estas preguntas anteriores

es un duplicado del anterior.

Mihai
fuente
2
@ GlenH7: esta parece una pregunta diferente. El otro es "si tiene funciones donde Allama By devuelve el mismo resultado, debería probar ambas Ay B". Esto es más sobre las pruebas que se superponen en lugar de las funciones bajo prueba. (Aunque es confuso ya que actualmente están nombrados).
Telastyn
1
Estrictamente hablando, estas pruebas no se superponen realmente (no tienen dependencia de éxito). Una función lambda: type('', (), {'__len__': lambda self: 2})()pasará la primera, pero no la segunda.
liori
1
@ GlenH7: FWIW, realmente no cambié la pregunta, solo traté de hacerla segura para mosquitos ;-) (@gnat: ¡sin ofender, solo bromeando!)
Doc Brown

Respuestas:

28

Puede haber valor, pero esto es un poco oloroso. O tus pruebas no están bien aisladas (ya que test_orderrealmente prueban dos cosas) o estás siendo demasiado dogmático en tus pruebas (haciendo que dos pruebas prueben lo mismo lógico).

En el ejemplo, fusionaría las dos pruebas juntas. Sí, significa que tienes múltiples afirmaciones. Demasiado. Todavía estás probando una sola cosa: el resultado de la función. A veces en el mundo real eso significa hacer dos controles.

Telastyn
fuente
Voté su respuesta, aunque se pierde un punto menor. En Python, la segunda prueba también fallará cuando my_functionno devuelva exactamente dos valores, sin ninguna afirmación, porque la asignación dará como resultado una excepción. Por lo tanto, en realidad no hay necesidad de usar múltiples afirmaciones y dos comprobaciones para probar lo mismo.
Doc Brown
@DocBrown: asumí lo mismo, pero no estoy familiarizado con los mensajes de error de Python para saber si puede tener valor tener un fallo de afirmación en lugar de una excepción / error aleatorio por razones informativas.
Telastyn
Creo que en la situación actual el mensaje de error probablemente sea lo suficientemente informativo. Pero en general, ese podría no ser el caso. Es por eso que estoy de acuerdo con usted en que el enfoque general para un caso como este debería ser pensar en una "fusión", utilizando dos afirmaciones. Si resulta que la prueba se puede simplificar aún más si se omite una de las afirmaciones, está bien.
Doc Brown
55
@DocBrown El otro valor al verificar explícitamente con una afirmación es que cualquier persona que examine la prueba tenga claro que se trata de una falla del código que se está probando, y no de la prueba en sí. Cuando mis pruebas encuentran excepciones inesperadas, siempre tengo que dedicar un tiempo a determinar cuál está realmente equivocado.
Chris Hayes
@ChrisHayes: Escribí "no hay necesidad", no "no hay valor" en él.
Doc Brown
5

Sus pruebas deben ser explícitas. No se infiere completamente que si text_length falla test_order falla.

No estoy seguro de cómo va en Python lo que has publicado, pero si len(result)es 3, el primero fallará pero el segundo puede pasar (y si no es en Python, seguro que en idiomas como JavaScript).

Como dijiste, quieres probar que la función devuelve dos números y que están en orden. Dos pruebas lo es.

El fantasma de Madara
fuente
1
It's not completely inferred that if text_length fails test_order fails- En Python, es decir, te dará una excepción.
Doc Brown
Creo que la pregunta es sobre el caso donde el fracaso de test_lengthimplica el fracaso de test_order. El hecho de que un par similar de pruebas escritas en Javascript no se comportara de la misma manera que estas dos pruebas de Python es irrelevante.
Dawood dice que reinstale a Mónica el
2
@DavidWallace: recuerde, la pregunta era "¿Es una buena práctica escribir test_length, o saltearlo"? En Javascript, necesita ambas pruebas para asegurarse de no perder un problema (cuando no combina las dos pruebas en una sola). En Python, puede omitir con seguridad la primera (que se niega en la primera oración de esta respuesta y se declara como "No estoy seguro" en la segunda). Honestamente, una buena respuesta se ve diferente. Sin embargo, no desestimé esta respuesta, ya que la mejor parte es la mención de JavaScript.
Doc Brown
44
@DavidWallace: dado que estamos aquí en programmers.com, no en stackoverflow.com, en mi humilde opinión, dar una respuesta que podría aplicarse a más de un idioma es mejor que una respuesta solo para un idioma en particular. Pero cuando se refiere a un idioma específico, la respuesta debe ser correcta sobre el idioma y no mezclar algunas propiedades.
Doc Brown
1
La cuestión es que la pregunta es "¿vale la pena escribir una prueba que es un subconjunto de otra prueba", y esta respuesta dice: "en algunos idiomas, ninguna de las pruebas es un subconjunto de la otra" y luego llega a la conclusión de que ambas pruebas son por lo tanto necesario Me dice como si alguien dijera: "su código no se compila en absoluto en C ++, y además, en C ++ una función solo puede devolver un valor, por lo que no necesita probarlo devuelve dos. Solo escriba una prueba" ;-)
Steve Jessop
2

El único valor de test_lengthaquí es que, si todo pasa, su sola presencia indica que se ha probado la "longitud".

Por lo tanto, es realmente innecesario tener ambas pruebas. Mantenga solo test_orderpero considere renombrarlo test_length_and_order.

Por cierto, encuentro el uso de nombres que comienzan con testun poco torpe. Soy un gran defensor de los nombres de las pruebas que realmente describen la condición que estás afirmando.

Dawood dice que reinstalar a Mónica
fuente
1
La testverruga es significativa para el marco de prueba de Python. Lo que, por supuesto, no necesita cambiar si eres fanático de él, pero cambia el peso de la discusión necesaria para evitar que alguien lo use ;-)
Steve Jessop
@SteveJessop Sí, sigo olvidando que es necesario. Cuando estaba escribiendo pruebas de Python hace un tiempo, tuve la costumbre de comenzar con todas test_that_, me gusta, test_that_return_values_are_in_orderetc. Tal vez una versión futura del marco de prueba evitará de alguna manera este requisito.
Dawood dice que reinstalar a Mónica el
@DavidWallace: puede cambiar el prefijo si lo desea.
Lie Ryan
1

Dejaría estas pruebas separadas si así es como han evolucionado para ser. Sí test_orderes probable que falle siempre que lo test_lengthhaga, pero definitivamente sabes por qué.

También estoy de acuerdo en que si test_orderapareció primero y encontró una falla comprobable, es posible que el resultado no fueran dos valores, agregando esa verificación como asserty cambiando el nombre de la prueba para que test_length_and_ordertenga sentido.

Si tuviera que verificar también que los tipos de valores devueltos eran enteros, lo incluiría en esta prueba de resultados "general".

Pero tenga en cuenta que ahora tiene una batería de pruebas para el resultado de my_function(). Si hay múltiples contextos (o, más probablemente, múltiples parámetros) para probar esto, ahora puede ser una subrutina para probar todos los resultados my_function().

Sin embargo, cuando escribo pruebas unitarias, normalmente pruebo el borde y los casos incorrectos por separado de una buena entrada y una salida normal (en parte porque la mayoría de mis pruebas "unitarias" son a menudo pruebas de mini integración), y a menudo con múltiples afirmaciones, que solo están rotas en pruebas separadas si fallan en formas en las que encuentro que quiero más información sin depurar.

Así que probablemente comenzar con sus pruebas por separado y ampliar test_lengtha test_length_and_typesy dejar test_orderaparte, suponiendo que este último se ve que es "proceso normal".

Mark Hurd
fuente