Simon Linder
Simon Linder

Reputation: 3438

Unit testing Html.Action and PartialView

I want to test some controller actions whose views contain Html.Action with PartialViews. But when debugging them I don't get the breakpoint that is in the action that I want to call through the view.
Here is my controller code:

public class SomeController
{ 
    public ActionResult MyAction()
    {
        return View();
    }

    public PartialViewResult SubAction()
    {
        return PartialView();
    }
}

The code in the MyAction view is simply:

@{
    ViewBag.Title = "MyAction";
}
@Html.Action("SubAction")

With my TestMethod I'd like to check if the correct ViewName is returned:

[TestMethod]
public void MyActionTest()
{
    SomeController controller = new SomeController();
    ViewResult result = controller.MyAction() as ViewResult;
    Assert.IsNotNull(result, "The result is not a view result.");
    Assert.AreEqual("some expected name", result.ViewName);
}

Another problem is that the result.ViewName is empty here and I don't know why that is. So this is another question unanswered. That problem is why I tried to debug my unit test and recognized that I cannot break into SubAction().

Any suggestions about that?

Cheers,
Simon

Upvotes: 0

Views: 2621

Answers (2)

archil
archil

Reputation: 39501

  1. ViewResult, and more generally, ActionResult is some kind of specification of what to execute when returning results to client. In other words, creating an instance of it (returning View() from controller) does create specification, but not execute it. MVC runtime captures that ActionResult returned from controller and Execute()s it. You cannot break inside the view because it is not executed yet - specification is just created. If you would have called Execute() method on it, as does mvc runtime, you would trigger view execution and hit the debugger.
  2. You cannot see the view name because you did not set it. From msdn

ViewResult.ViewName gets or sets the name of the view to render.

And if you do not set it when returning View, it is only populated when the ViewResult is Executed(), see the explanation above.

You should only test controller and its iteraction with views, repositories, etc. when unit testing controller. You should not need to debug the view when testing controller. If you need to test SubAction, write the separate test for it. You could use MvcContrib.TestHelpers for simpler unit testing your controllers.

Upvotes: 2

Zasz
Zasz

Reputation: 12538

When you are running your unit test, the view is not rendered. The @Html.Action("SubAction") is only executed when the view is rendered. When you say : "I want to test some controller actions whose views contain Html.Action with PartialViews", you are actually saying that you want to test the views and logic inside views.

The reason your break in SubAction is not reached is because the MyAction view is not rendered at all. The way to go about testing these kinds of scenarios is :

  1. In Test 1 Check if MyAction is returning a ViewResult whose internal view-model has all the correct values in its properties.
  2. In Unit test 2 Check if SubAction is returning a ViewResult whose internal view-model has all the correct values in its properties.
  3. ViewName is a property that is only populated if you call return View("some other non-convetional view") then result.ViewName will be = "some other non-convetional view" You don't test the view name for those using convention defaults because you trust the framework to wire it up right.

Upvotes: 3

Related Questions