If I create a new MVC 5 project (with unit tests) and make a new superclass for my controllers using a snippet from a popular SO answer it is easy to render the contents of a view into a string:
HomeController.cs
public class HomeController : StringableController
{
public ActionResult StringIndex()
{
string result = RenderRazorViewToString("Index", null);
return Content(result);
}
}
Now if I visit /Home/StringIndex
, I get back the raw HTML for that view. Neat (even if not very useful)! But over in the .Tests project, if I try to test StringIndex() in a unit test...
HomeControllerTest.cs
[TestClass]
public class HomeControllerTest
{
[TestMethod]
public void StringIndex()
{
HomeController controller = new HomeController();
ContentResult result = controller.StringIndex() as ContentResult;
string resultString = result.Content;
Assert.IsTrue(resultString.Contains("Getting started"));
}
}
...no such luck. Calling controller.StringIndex()
from the unit test creates an ArgumentNullException
when System.Web.Mvc.ViewEngineCollection.FindPartialView()
is called in the aforementioned snippet, on account of controllerContext
being null
. I have tried a few Moq based approaches (modified versions of SetUpForTest()
and MvcMockHelpers
) to mock up the controllerContext
, but this may be the wrong approach, because 1) neither approach was specifically tailored to unit testing within Visual Studio, and 2) I am not entirely sure what needs to be real vs. mocked in order to successfully render the view.
Is it possible -in Visual Studio unit tests- to create a controllerContext that's capable of getting RenderRazorViewToString() to work?
EDIT to clarify my goal: I don't want to test the inner workings of RenderRazorViewToString()
(which is just a tool being used for the job); I want my unit test to be able to analyze the actual HTML that would be returned from the controller in a normal case. So if (as a bad, silly example) my Index.cshtml is just <h2>@DateTime.Now.Year</h2>
, then Assert.IsTrue(resultString.Contains("<h2>2013</h2>
"));
(as the last line in HomeControllerTest.StringIndex()
) will succeed.