Unit testing an exception thrown into a controller
I am currently testing a module where an error is thrown when submitting invalid form collection data.
An exception is thrown in the HttpPost Index ActionResult method shown below:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(FormCollection formCollection, PaymentType payType, string progCode)
{
ActionResult ar = redirectFromButtonData(formCollection, payType, progCode);
if (ar != null)
{
return ar;
}
else
{
throw new Exception("Cannot redirect to payment form from cohort decision - Type:[" + payType.ToString() + "] Prog:[" + Microsoft.Security.Application.Encoder.HtmlEncode(progCode) + "]");
}
}
so far I have written a test that successfully removes the exception (I tested this by enabling code coverage which I use to see what code is being executed by each individual test), but currently the test is not running because I don't have it yet a specific way of testing that an exception has been thrown, the code for this test can be found below:
[TestMethod]
public void Error_Is_Thrown_If_HVM_FormCollection_Data_Is_Incorrect()
{
var formCollection = new FormCollection();
formCollection.Add("__RequestVerificationToken", "__RequestVerificationToken");
formCollection.Add("invalid - invalid", "invalid- invalid");
var payType = new PaymentType();
payType = PaymentType.deposit;
var progCode = "hvm";
var mocks = new MockRepository();
var httpRequest = mocks.DynamicMock<HttpRequestBase>();
var httpContext = mocks.DynamicMock<HttpContextBase>();
controller.ControllerContext = new ControllerContext(httpContext, new RouteData(), controller);
mocks.ReplayAll();
httpRequest.Expect(r => r.Url).Return(new Uri("http://localhost:8080/hvm/full/self/")).Repeat.Any();
httpContext.Expect(c => c.Request).Return(httpRequest).Repeat.Any();
var result = controller.Index(formCollection, payType, progCode);
}
I have considered using annotation [ExpectedException(typeof(Exception)]
, can this be used in this case?
source to share
I took the liberty of modifying my test code to slightly align the latest rhino features. This is no longer required to create MockRepository
, you can use a static class MockRepository
and call GenerateMock<>
. I also translated your instance of SuT (system under test) below the spec for you mocks.
Example with Nunit (I have better experience with Nunit than with MSTest. Mainly because Nunit releases more often and has more robust feature sets. Again, not sure if it works with TFS, but it shouldn't be difficult to find out).
[Test] // Nunit
[ExpectedException(typeof(Exception)) // NOTE: it wise to throw specific
// exceptions so that you prevent false-positives! (another "exception"
// might make the test pass while it a completely different scenario)
public void Error_Is_Thrown_If_HVM_FormCollection_Data_Is_Incorrect()
{
var formCollection = new FormCollection();
formCollection.Add("__RequestVerificationToken", "__RequestVerificationToken");
formCollection.Add("invalid - invalid", "invalid- invalid");
var payType = new PaymentType();
payType = PaymentType.deposit;
var progCode = "hvm";
var httpRequest = MockRepository.GenerateMock<HttpRequestBase>();
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
// define behaviour
httpRequest.Expect(r => r.Url).Return(new Uri("http://localhost:8080/hvm/full/self/")).Repeat.Any();
httpContext.Expect(c => c.Request).Return(httpRequest).Repeat.Any();
// instantiate SuT (system under test)
controller.ControllerContext = new ControllerContext(httpContext, new RouteData(), controller);
// Test the stuff, and if nothing is thrown then the test fails
var result = controller.Index(formCollection, payType, progCode);
}
And it's almost the same deal with MStest, except that you need to define the expected exception slightly larger than oldskool.
[TestMethod] // MStest
public void Error_Is_Thrown_If_HVM_FormCollection_Data_Is_Incorrect()
{
try
{
var formCollection = new FormCollection();
formCollection.Add("__RequestVerificationToken", "__RequestVerificationToken");
formCollection.Add("invalid - invalid", "invalid- invalid");
var payType = new PaymentType();
payType = PaymentType.deposit;
var progCode = "hvm";
var httpRequest = MockRepository.GenerateMock<HttpRequestBase>();
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
// define behaviour
httpRequest.Expect(r => r.Url).Return(new Uri("http://localhost:8080/hvm/full/self/")).Repeat.Any();
httpContext.Expect(c => c.Request).Return(httpRequest).Repeat.Any();
// instantiate SuT (system under test)
controller.ControllerContext = new ControllerContext(httpContext, new RouteData(), controller);
// Test the stuff, and if nothing is thrown then the test fails
var result = controller.Index(formCollection, payType, progCode);
}
catch (Exception)
{
Assert.Pass();
}
Assert.Fail("Expected exception Exception, was not thrown");
}
If you have this piece of work, you can refactor it for better re-usability via the link provided: Fix NUnit Exception in MS TEST .
source to share
The easiest way to test this is to wrap the call in try-catch and set a boolean variable if the catch block is executed. Something like:
var exceptionIsThrown = false;
ActionResult result;
try
{
result = controller.Index(formCollection, payType, progCode);
}
catch(Exception)
{
exceptionIsThrown = true;
}
source to share