In Typemock we use both NUnit and MSTest to run our unit tests. This practice enables us to check that Isolator works fine on both unit testing framework. Most of NUnit attributes can be translated fully into MSTest attributes (and vise-versa) there is one attribute we tend to use that works differently in MSTest - ExpectedException.
ExpectedException attribute is used to specify that a test should throw an exception to pass, both framework let the user define the type of the exception thrown (i.e. typeof(ApplicationException)) the big difference between the framework lies in the 2nd (optional) parameter of that attribute - the Message.
While NUnit compares the massage to the exception's message MSTest does not. At first I though it was a bug but further investigation revealed that this was done intentionally, Microsoft decision was that the message should be only descriptive and used to associate a message to the exception and not check it.
So what could a TDD developer do if he wants to write a test that checks the exception message as well?
One solution is to add code to the test to check the exception's message:
The problem with this solution is that whenever I need to check an exception message I need to write ~4 more lines of code that makes my test less readable and somewhat error prone.
After digging a bit on the net I found a better solution, it seems that both XUnit and MBUnit uses Assert.Throws method instead of an attribute to check for expected exceptions.
First I've created a new class MyAssert that handles the exception verification logic:
After using MyAssert.Throws for a while I have to say I prefer it to using ExpectedException attribute because of the specific meaning it bring to my unit tests.
ExpectedException attribute is used to specify that a test should throw an exception to pass, both framework let the user define the type of the exception thrown (i.e. typeof(ApplicationException)) the big difference between the framework lies in the 2nd (optional) parameter of that attribute - the Message.
While NUnit compares the massage to the exception's message MSTest does not. At first I though it was a bug but further investigation revealed that this was done intentionally, Microsoft decision was that the message should be only descriptive and used to associate a message to the exception and not check it.
So what could a TDD developer do if he wants to write a test that checks the exception message as well?
One solution is to add code to the test to check the exception's message:
[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;
}
}
You can read more about this method at IMistaken Blog.The problem with this solution is that whenever I need to check an exception message I need to write ~4 more lines of code that makes my test less readable and somewhat error prone.
After digging a bit on the net I found a better solution, it seems that both XUnit and MBUnit uses Assert.Throws method instead of an attribute to check for expected exceptions.
First I've created a new class MyAssert that handles the exception verification logic:
public class MyAssert
{
public static void Throws<T>(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));
}
}
Then all I needed to do is use the new class whenever I needed to test for an exception and verify its message:[TestMethod]
public void AddNewUser_UserEmailIsEmpty_ThrowException()
{
MyAssert.Throws<ApplicationException>(
() => UserConnector.AddNewUser("user1", ""), "Error: user's email address missing");
}
Although this solution seems more complicated at first it does have two advantages:- I don't need to write the verification logic anymore
- I can specify the exact line in which I expect the exception to be thrown from.
After using MyAssert.Throws for a while I have to say I prefer it to using ExpectedException attribute because of the specific meaning it bring to my unit tests.



1 comments:
Post a Comment