Index view在Listing 3中。注意文件名是Index.htm。SimpleViewEngine 返回了一个.htm 文件。
Listing 3 – Index.htm
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Tip 25</title> </head> <body> Here is the first message: {message} <br /> Here is the second message: <b>{message2}</b> </body> </html> |
Figure 1 - Index view呈现的页面

创建一个伪造的Controller Context
SimpleViewEngine.RenderView()方法并不返回一个值。RenderView()方法将值直接写入HttpContext.Response对象中。因此,为了单元测试views,我们必须能够伪造HttpContext 对象,以便我们能够暗中监视添加到该对象中的值。
在我以前的两篇帖子中,我演示了如何伪造ControllerContext 和HttpContext 对象:
| http://weblogs.asp.net/stephenwalther/archive/2008/06/30/asp-net-mvc-tip-12-faking-the-controller-context.aspx http://weblogs.asp.net/stephenwalther/archive/2008/07/02/asp-net-mvc-tip-13-unit-test-your-custom-routes.aspx |
在以前的这些帖子中,我演示了伪造ControllerContext 和 HttpContext对象是很有用的,当你需要单元测试Session State, Cookies, Form fields, 和 Route Tables时。
本文结尾处下载的代码中包含一个MvcFakes项目。我已经添加了一个伪造的HttpResponse 对象到一批伪造对象中,你可以在单元测试中使用这些伪造对象。
为View创建一个单元测试
既然我们已经创建了一个自定义的View Engine和一批伪造对象,那么我们就可以单元测试view了。Listing 4中的测试类测试了HomeController.Index() action返回的Index view。
Listing 4 – HomeControllerTest.cs (C#)
| namespace Tip25Tests.Controllers { [TestClass] public class HomeControllerTest { private const string viewsPath = @"C:\Users\swalther\Documents\Common Content\Blog\Tip25 Custom View Engine\CS\Tip25\Tip25\Views"; [TestMethod] public void Index() { // Setup controller HomeController controller = new HomeController(); controller.ViewEngine = new SimpleViewEngine(viewsPath); // Setup fake controller context var routeData = new RouteData(); routeData.Values.Add("controller", "home"); var fakeContext = new FakeControllerContext(controller, routeData); // Execute ViewResult result = controller.Index() as ViewResult; result.ExecuteResult(fakeContext); string page = fakeContext.HttpContext.Response.ToString(); // Verify StringAssert.Contains(page, "<title>Tip 25</title>"); StringAssert.Contains(page, "Welcome to ASP.NET MVC!", "Missing Message"); StringAssert.Contains(page, "<b>Using a custom View Engine</b>", "Missing Message2 with bold"); } } } |
第二部分准备伪造的ControllerContext 对象。注意你必须传递一个controller name 给FakeHttpContext 类的构造函数。
接着,HomeController.Index() action方法被调用。这个action 返回一个ViewResult。接着,该ViewResult 在伪造的HttpContext中被执行。最后,HttpResponse.ToString() 方法被调用来获得SimpleViewEngine写入HttpResponse 对象的值。
最后一部分证实view 呈现的页面包含三个子字符串。第一个是HTML 页面的title 被证实。第二,证实存在来自ViewData 的两个messages。注意该测试要证实第2个message 是否是粗体显示。
总结
在这篇帖子中,我展示了如何扩展你的单元测试来覆盖views。通过利用自定义的View Engine,你可以为models, controllers, 和 views创建单元测试。

