I'm doing some simple MS unit tests on my standard, nothing special controller.
When I check the ViewName
proprty, from the returned ViewResult
object, it's ""
(empty).
I'm under the impression that the ViewName
is implied by the name of the View
(as suggested by this MS article on ASP.NET MVC controller testing).
BTW, when I test the ViewData, it's all there and correct.
Here's the code I have...
public ActionResult Index(int? page, string tag) { if (page == null || page <= 0) { page = 1; } var viewData = new IndexViewData { ... my property setters, etc ... }; return View(viewData); } [TestMethod] public void Index_Action_Should_Return_Index_View_For_Default_HomePage() { // Arrange. var controller = PostController; // Wrapper, cause I use D.I. // Act. ViewResult viewResult = controller.Index(null, null) as ViewResult; // Assert. Assert.IsNotNull(viewResult); Assert.AreEqual("Index", viewResult.ViewName); // This is false/fails. var indexViewData = viewResult.ViewData.Model as IndexViewData; Assert.IsNotNull(indexViewData); // This is true. }
We can write an unit test for this controller method by following steps: Create the test data which is returned when our service method is called. We use a concept called test data builder when we are creating the test data for our test.
The answer to the more general question is yes, you should unit test everything you can. Doing so creates a legacy for later so changes down the road can be done with peace of mind. It ensures that your code works as expected.
unit tests do not run in the "MVC environment." They will run within the scope of the test runner, be that nunit, resharper,....
First we need to add an employee class in the Models folder. Following is the Employee class implementation. We need to add EmployeeController. Right-click on the controller folder in the solution explorer and select Add → Controller.
The ViewName is only present when you set it in the ViewResult. If your View name matches your controller name, then I would check to ensure that the ViewName is null or empty as that would be (IMO) the correct behavior since you wouldn't want to set a name on the view. I only check that the ViewName is set when I intend that the View to be returned does not match the action -- say, when returning the "Error" view, for example.
EDIT: The following is the source for ExecuteResult in ViewResultBase.cs (from RC1, I don't have the source for RTW on my Macintosh). As you can see it checks to see if the ViewName has been set directly and if not, it pulls it from the action in the controller context's route data. This only happens in ExecuteResult, which is invoked AFTER your controller's action has completed.
public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (String.IsNullOrEmpty(ViewName)) { ViewName = context.RouteData.GetRequiredString("action"); } ViewEngineResult result = null; if (View == null) { result = FindView(context); View = result.View; } ViewContext viewContext = new ViewContext(context, View, ViewData, TempData); View.Render(viewContext, context.HttpContext.Response.Output); if (result != null) { result.ViewEngine.ReleaseView(context, View); } }
I personally found the testing facilities provided by MVC2 to be somewhat clumsy. I'm guessing there is something better already extant, but I ended up creating a simple class to test actions. I modeled the interface (the implementation is another story) on a class provided by the excellent open source Java MVC framework Stripes called MockRoundTrip
.
Here is the method used to get the action destination page when testing actions, called getTripDestination()
. It returns the correct result irrespective of whether the viewname is explicitly set or not
//Get the destination page of the request, using Runtime execution pattern of MVC, namely //if no ViewName is explicitly set in controller, ViewResult will have an empty ViewName //Instead, current action name will be used in its place public string getTripDestination() { RouteData routeData = getRouteData(); ViewResult viewResult = (result is ViewResult) ? (ViewResult)result : null; string tripDestination = (viewResult != null) ? viewResult.ViewName : ""; return (tripDestination != "") ? tripDestination : (String)routeData.Values["action"]; } private RouteData getRouteData() { HttpContextBase context = controller.ControllerContext.RequestContext.HttpContext; return RouteTable.Routes.GetRouteData(context); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With