Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing my controller method results in an empty ViewName?

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. } 
like image 812
Pure.Krome Avatar asked Apr 05 '09 06:04

Pure.Krome


People also ask

Do we write unit test for controller?

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.

Should every method be unit tested?

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.

Can a unit test be performed on an MVC application without running the controllers in an ASP NET process?

unit tests do not run in the "MVC environment." They will run within the scope of the test runner, be that nunit, resharper,....

How do I create a controller unit test?

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.


2 Answers

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);         }     } 
like image 184
tvanfosson Avatar answered Sep 19 '22 02:09

tvanfosson


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);     } 
like image 24
Zac Avatar answered Sep 22 '22 02:09

Zac