Mejores pruebas unitarias con FluentAssertions
La semana pasada hablamos un poco sobre las pruebas unitarias y los beneficios que estas tienen. También habamos sobre cómo es que podemos comenzar a crearlas usando Visual Studio y C#. Y aprovechando la inercia, esta vez les traigo un #NuGetRecomendado que puede ayudarte a hacer las puebras unitarias más sencillas.
En uno de los videos mencioné que una prueba unitaria usualmente se compone de tres pasos, y este paquete concierne directamente a la tercera: Assert o comprobar.
Nadie desea que sus pruebas unitarias fallen, pero seguramente sí desean que, en caso de que fallen, les den la mayor información posible.
Ahora sí, mira este fragmento de código:
string result = "That C# guy";
Assert.IsTrue(result.StartsWith("That"));
Assert.IsTrue(result.EndsWith("guy"));
Assert.IsTrue(result.Contains("Java"));
Mediante los asserts se está corroborando que la cadena:
- Comience con "That"
- Termine con "guy"
- Contenga "Java"
Ahora mira el siguiente usando FluentAssertions
// Arrange
// Act
string result = "That C# guy";
// Assert
result.Should().StartWith("That").And.EndWith("guy").And.Contain("Java");
En una simple "línea" se realizan varias comprobaciones sobre un mismo elemento, lo cual no solo es conveniente, sino que dada la naturaleza fluida de los métodos, el código se torna más legible y entendible a simple vista. Pero no solo eso, sino que los mensajes de error también se tornan más descriptivos para que el responsable de analizar los resultados de las pruebas las encuentre fácil de entender. Ya que el error mostrado es más descriptivo que si usáramos un Assert
tradicional:
Should()
La base de FluentAssertions es el método Should
que en inglés significa "debería". Sobre el valor de retorno de este se permite seguir encadenando métodos para hacer que nuestra prueba unitaria compruebe lo que deseamos, como por ejemplo en el siguiente bloque de código se comprueba la longitud de una cadena y se le añade un mensaje para mostrar en caso de que falle:
// Normal unit test
string actual = "That C# guy";
Assert.AreEqual(8, actual.Length);
// With FluentAssertions
string result = "That C# guy";
result.Should().HaveLength(8, "because I love the number 8");
Cuando la prueba falla:
Arreglos
También permite trabajar con arreglos. Nuevamente es necesario comenzar con Should
. Para este caso se comprueba que el arreglo tenga una determinada longitud, sin embargo, también tiene opciones para comprobar el contenido del arreglo y demás propiedades de este:
// Normal unit test
var array = new int[] { 10, 5 };
array.Should().HaveCount(3);
// With FluentAssertions
var array = new int[] { 10, 5 };
Assert.AreEqual(3, array.Length);
Cuando la prueba falla:
BeOfType
Pero no solo funciona con arreglos y cadenas, sino que también permite trabajar con objetos. Por ejemplo, en el siguiente caso estamos realizando una comprobación sobre un object
. Con FluentAssertions se corrobora que sea un arreglo de enteros y que dicho arreglo contenga 10 elementos.
// Normal unit test
object thing = new int[] { 10, 5, 5 };
var arreglo = thing as int[];
Assert.IsNotNull(arreglo);
Assert.AreEqual(10, arreglo.Length);
// With FluentAssertions
object array = new int[] { 10, 5, 5 };
array.Should().BeOfType<int[]>()
.Which.Should().HaveCount(10, "some weird reason");
Cuando la prueba falla:
Dictionary
FluentAssertions también puede comprobar el contenido de una colección, como un Dictionary
, además de realizar la comprobación sobre alguna propiedad de el contenido de dicha colección:
// Normal unit test
var computerScientists = new Dictionary<string, string>();
Assert.IsTrue(computerScientists.ContainsValue("Grace Hopper"));
var value = computerScientists["Grace Hopper"];
Assert.AreEqual(12, value.Length);
// With FluentAssertions
var computerScientists = new Dictionary<string, string>();
computerScientists.Should()
.ContainValue("Grace Hopper", "she's awesome")
.Which.Length.Should().Be(12);
Cuando la prueba falla:
Excepciones
Otro gran uso de FluentAssertions es cuando es necesario probar que nuestro código lanza las excepciones correctas. Usualmente con C# puro tendríamos que marcar el método de la prueba con ExpectedException
, mientras que con nuestro paquete de NuGet basta con usar el método ShouldThrow
.
// Normal unit test
[TestMethod]
[ExpectedException(typeof(FormatException))]
public void Normal_ShouldThrowException()
{
Action action = () =>
{
var i = 1;
var t = 1 / (i - 1);
};
action();
}
// With FluentAssertions
[TestMethod]
public void FluentAssertions_ShouldThrowException()
{
Action action = () =>
{
var i = 1;
var t = 1 / (i - 1);
};
action.ShouldThrow<FormatException>("other reason");
}
Cuando la prueba falla:
Uso
Recuerda que este es un paquete de NuGet que debe ser instalado en tu proyecto de pruebas, no en el proyecto que vas a probar. Basta con instalar paquete de NuGet.
PM> Install-Package FluentAssertions
O... o, siempre puedes descargar el código fuente para integrarlo y hacerle las modificaciones que desees.