I mentioned above that the new ActionResult approach can
make unit testing controllers much easier (and avoid the need to use mocking
for common scenarios). Let's walk through an example of this in action.
Consider the simple NumberController class below:
Figure 7
This Controller class has an "IsEvenNumber" action
method that takes a number as a URL argument. The IsEvenNumber action
method first checks whether the number is negative - in which case it redirects
the user to an error page. If it is a positive number it determines
whether the number is even or odd, and renders a view template that displays an
appropriate message:
Figure 8
Writing unit tests for our
"IsEvenNumber" action method is pretty easy thanks to the new
ActionResult approach.
Below is an example unit test that verifies
that the correct Http redirect occurs when a negative number is supplied (for
example: /Number/IsEvenNumber/-1):
Figure 9
Notice above how we did not need to mock any
objects to test our action method. Instead we simply instantiated the
NumberController class and called the action method directly (passing in a
negative number) and assigned the return value to a local "result"
variable. I used the C# "as type" syntax above to cast the
"result" variable as a strongly typed "HttpRedirectResult"
type.
What is nice about the C# "as"
keyword is that it will assign the value as null instead of throwing an
exception if the cast fails (for example: if the action method returned a
RenderViewResult instead). This means I can easily add an assertion check
in my test to verify that the result is not null in order to verify that an
Http redirect happened. I can then add a second assertion check to verify
that the correct redirect URL was specified.
Testing the scenarios where non-zero numbers
are passed in is also easy. To do this we'll create two test methods -
one testing even numbers and one testing odd numbers. In both tests we'll
assert that a RenderViewResult was returned, and then verify that the correct
"Message" string was passed within the ViewData associated with the
view:
Figure 10
We can then right click on our NumberControllerTest class
inside VS 2008 and choose the "Run Tests" menu item:
Figure 11
This will execute our three unit tests
in-memory (no web-server required) and report back on whether our
NumberController.IsEvenNumber() action method is performing the right behavior:
Figure 12
Note: with this week's source drop you still need to use
mocking to test the TempData property on Controllers. Our plan is to not
require mocking to test this with the ASP.NET MVC Preview 3 drop in a few
weeks.