22 de julio de 2015

ExpectedException in MSTest does not check the exception message

Cuando se utiliza ExpectionException para verificar el emnsaje de una excepcion en MSTest, simplemente utilizando esto
[TestMethod]
[ExpectedException(typeof(ValidationException), "Postcode must be provided")]
  publicvoid PostcodeIsNullOrWhitespace()
   {
   //etc.
   } 
si verifica que la excepción se ha llamado pero no verifica el mensaje que se recibe, para verificar el mensaje de la excepción se puede utilizar
[TestMethod]
[ExpectedException(typeof(ApplicationException))]
public void AddNewUser_UserEmailIsEmpty_ThrowException()
{
    try
    {
        // This line should throw an exception
        UserConnector.AddNewUser("user1", "");
    }
    catch (ApplicationException exc)
    {
        Assert.AreEqual("Error: user's email address missing", exc.Message);
        throw;
    }
}
El problema con esta solucion es que cada vez que necesite verificar un mensaje de excepción deberé escribir un test unitario que especifique el mensaje, lo mejor sera crear una clase que verifique el mensaje por mi y luego simplemente en cada test unitario hacer una referencia a esa clase
public class MyAssert
{
    public static void Throws(Action action, string expectedMessage) where T : Exception
    {
        try
        {
            action.Invoke();
        }
        catch (T exc)
        {
            Assert.AreEqual(expectedMessage, exc.Message);
 
            return;
        }
 
        Assert.Fail("Exception of type {0} should be thrown.", typeof(T));
    }
}
y la manera de utilizarlo en los test seria la siguiente:
[TestMethod]
public void AddNewUser_UserEmailIsEmpty_ThrowException()
{
    MyAssert.Throws(
        () => UserConnector.AddNewUser("user1", ""), "Error: user's email address missing");
}
Claro que lo anterior va tener detractores por el uso de throws así que investigando un poco en internet encontré esta función, la dejo como un complemento mas profesional a mi humilde aportacion
///
        /// Runs the action statement and asserts that it causes an exception with the expected type and message
        ///
        ///
        ///
        ///
        publicstaticvoid AssertRaisesException(Action action, string expectedMessage)
            where TException : Exception
        {
            try
            {
                action();
                Assert.Fail("Call suceeded. Expected exception of type: {0} with message: {1}".FormatWith(typeof(TException).Name, expectedMessage));
            }
            catch (Exception ex)
            {
                if (ex isAssertFailedException)
                    throw ex;
 
                var exception = ex as TException;
                Assert.IsNotNull(exception, "Expected exception of type: {0}, actual type: {1}".FormatWith(typeof(TException).Name, ex.GetType().Name));
                Assert.AreEqual(expectedMessage, exception.Message, "Expected message: {0}".FormatWith(expectedMessage));
            }
        }
el uso de la clase anterior al momento de realizar una prueba unitaria es el siguiente:
[TestMethod]
[ExpectedException(typeof(ValidationException))]
 public void PostcodeIsNullOrWhitespace()
  {
  var postcode = " ";
  AssertRaisesException(() => ValidatePostcode(postcode), "Postcode must be provided");
  //etc.
  }
miércoles, julio 22, 2015