unit-testing - test - tipos de pruebas unitarias
¿Es una mala práctica tener más de una afirmación en una prueba unitaria? (9)
¡Definitivamente debería usar solo una afirmación en el método de prueba! El uso de muchas afirmaciones puede ser el olor del código que está probando más de una cosa. Además, existe la posibilidad de que alguien pueda agregar una nueva afirmación en su prueba en lugar de escribir otra. ¿Y cómo puedes entender cómo terminaron tus otros asertos cuando falló el primero?
También puede encontrar interesante este artículo: https://timetocode.wordpress.com/2016/06/01/zen-of-unit-testing/
¿Es una mala práctica tener más de una afirmación en una prueba unitaria? ¿Importa?
Coloque todas las afirmaciones que desee. Seriamente.
Intento afirmar cada paso del camino e incluir el objetivo específico de mi prueba.
No importa. Lo único que importa es que las pruebas de su unidad cubrirán todos los posibles errores.
Este es un ejemplo de "exceso de pensamiento".
No lo considero una mala práctica. Las pruebas unitarias pueden hacer lo que quieran: afirmar, iniciar sesión en archivos, enviar mensajes SMS insultantes a la administración, cualquier cosa.
El posible problema es que la complejidad adicional puede cambiar el comportamiento del programa bajo prueba, pero rara vez ocurre si se tiene cuidado y se puede descubrir de todos modos.
No, no es una mala práctica. Si el método que está probando devuelve una clase, debe probar las diferentes variables que deberían haberse establecido. Para este propósito, también podría usar una prueba unitaria.
Sin embargo, si está probando varias funciones en una prueba unitaria, no será tan claro cuándo falla qué características causaron el problema. Recuerde que las pruebas unitarias son su amigo, así que permítale que lo ayude. Haga que esté fácilmente disponible para ver qué salió mal para que pueda solucionarlo.
Para mí es muy común tener más de una afirmación en una prueba unitaria. Normalmente tengo una afirmación de una condición previa y luego una afirmación para la condición de publicación esperada.
Considerar:
assert(list.isEmpty());
FetchValues(list);
assert(list.count == expectedItemCount);
AssertValuesMatch(list,expectedValues);
Sí, podría dividir las dos condiciones de publicación en dos pruebas, pero dependiendo del costo de FetchValues podría ralentizar el proceso de prueba en general innecesariamente.
Sus pruebas unitarias deben ser razonablemente finas. Por lo general, cuantas menos afirmaciones, más probable es que su prueba se dirija a una función específica y no mezcle las pruebas para funciones múltiples en la misma prueba. ¿Esto significa que todas las pruebas solo deberían tener una afirmación? No, pero lo consideraría un "olor a prueba" si encontrara varios asertos, probando potencialmente varias cosas en la misma prueba unitaria. Trate este "olor" como lo haría con un código olfateando y refactorizando la prueba para refinarlo de manera que solo pruebe una "cosa", incluso si requiere más de una afirmación.
Por ejemplo, ahora estoy haciendo un proyecto de MVC y una de las pruebas que escribo es que la acción muestra la vista correcta. En realidad, puede haber varios de estos si diferentes rutas de código pueden dar lugar a diferentes puntos de vista. Así es como defino que es la vista correcta: el resultado es el tipo correcto y tiene el nombre correcto. Esto requiere dos afirmaciones, pero solo estoy probando una cosa.
var result = controller.Action() as ViewResult;
Assert.IsNotNull( result );
Assert.AreEqual( viewName, result.ViewName );
Podría hacer algo similar con el modelo, pero no probaría que el modelo es correcto en la misma prueba que verificando la vista porque estos son aspectos diferentes del comportamiento del código. Podría cambiar el modelo o vista esperada y al ponerlo en una prueba separada, solo se deben cambiar las pruebas relacionadas con esa característica del método.
Una "prueba de unidad" debe probar 1 unidad, por lo tanto, sea lo más pequeño posible y pruebe solo 1 cosa determinada. Sugeriría tener solo 1 afirmación
PERO creo que está bien tener 2 afirmaciones siempre y cuando no estén una detrás de la otra.
Mal ejemplo
public void ValidateRulesEntry_Valid_ValidConditionsFromFile()
{
string condition = "Target.HasValue";
string returnMessage;
bool successFul = CodeParserTryParseCondition(condition, out returnMessage);
Assert.IsTrue(successFul);
Assert.IsFalse(string.IsNullOrEmpty(returnMessage));
Assert.IsTrue(returnMessage == "OK");
}
A veces tengo exactamente un caso de afirmación por prueba, pero creo que con más frecuencia tengo varias afirmaciones assert
.
He visto el caso al que se le escapa @Arkain, donde un pedazo de código muy grande tiene un conjunto de pruebas de unidad única con solo unos pocos casos de prueba, y todos están etiquetados testCase1
, testCase2
, etc., y cada caso de prueba tiene cientos de afirma. Y aún mejor, cada condición generalmente depende de los efectos secundarios de la ejecución previa. Cada vez que falla la compilación, invariablemente en dicha prueba unitaria, lleva bastante tiempo determinar dónde estaba el problema.
Pero el otro extremo es lo que sugiere su pregunta: un caso de prueba por separado para cada condición posible. Dependiendo de lo que está probando, esto podría tener sentido, pero a menudo tengo varias assert
por caso de prueba.
Por ejemplo, si escribiste java.lang.Integer
, es posible que tengas algunos casos que se vean así:
public void testValueOf() {
assertEquals(1, Integer.valueOf("1").intValue());
assertEquals(0, Integer.valueOf("0").intValue());
assertEquals(-1, Integer.valueOf("-1").intValue());
assertEquals(Integer.MAX_VALUE, Integer.valueOf("2147483647").intValue());
assertEquals(Integer.MIN_VALUE, Integer.valueOf("-2147483648").intValue());
....
}
public void testValueOfRange() {
assertNumberFormatException("2147483648");
assertNumberFormatException("-2147483649");
...
}
public void testValueOfNotNumbers() {
assertNumberFormatException("");
assertNumberFormatException("notanumber");
...
}
private void assertNumberFormatException(String numstr) {
try {
int number = Integer.valueOf(numstr).intValue();
fail("Expected NumberFormatException for string /"" + numstr +
"/" but instead got the number " + number);
} catch(NumberFormatException e) {
// expected exception
}
}
Algunas reglas simples que puedo pensar a mano para saber cuántas afirmaciones poner en un caso de prueba:
- No tiene más de una
assert
que dependa de los efectos secundarios de la ejecución previa. - Los grupos
assert
juntos que prueban la misma función / función o faceta de la misma, sin necesidad de la sobrecarga de los casos de prueba de unidades múltiples cuando no es necesario. - Cualquiera de las reglas anteriores debe ser anulada por la practicidad y el sentido común. Probablemente no desee un millar de casos de prueba con una sola afirmación en cada uno (o incluso varios asertos) y no quiere un solo caso de prueba con cientos de afirmaciones
assert
.