你的web application可以测试的部分越多,你就对应用程序的修改不会带来新的bug越有信心。ASP.NET MVC让你很容易测试models 和controllers。在这篇帖子中,我将解释如何单元测试views。
创建一个自定义View Engine
让我们从创建一个自定义的View Engine开始。Listing 1中包含了一个叫做SimpleViewEngine的非常简单的View Engine。
Listing 1 – SimpleViewEngine.cs (C#)
namespace Tip25
{
public class SimpleViewEngine : IViewEngine
{
private string _viewsFolder = null;
public SimpleViewEngine()
{
if (HttpContext.Current != null)
{
var root = HttpContext.Current.Request.PhysicalApplicationPath;
_viewsFolder = Path.Combine(root, "Views");
}
}
public SimpleViewEngine(string viewsFolderPhysicalPath)
{
_viewsFolder = viewsFolderPhysicalPath;
}
public void RenderView(ViewContext viewContext)
{
if (_viewsFolder == null)
throw new NullReferenceException("You must supply a viewsFolder path");
string fullPath = Path.Combine(_viewsFolder, viewContext.ViewName) + ".htm";
if (!File.Exists(fullPath))
throw new HttpException(404, "Page Not Found");
// Load file
string rawContents = File.ReadAllText(fullPath);
// Perform replacements
string parsedContents = Parse(rawContents, viewContext.ViewData);
// Write results to HttpContext
viewContext.HttpContext.Response.Write(parsedContents);
}
public string Parse(string contents, ViewDataDictionary viewData)
{
return Regex.Replace(contents, @"\{(.+)\}", m => GetMatch(m, viewData));
}
protected virtual string GetMatch(Match m, ViewDataDictionary viewData)
{
if (m.Success)
{
string key = m.Result("$1");
if (viewData.ContainsKey(key))
return viewData[key].ToString();
}
return String.Empty;
}
}
}
注意SimpleViewEngine 实现了IViewEngine 接口。该接口有一个RenderView()方法必须实现。
在Listing 1中,RenderView()方法从硬盘中加载一个文件,并用ViewData中的项目来替换文件中的标签(tokens)。 在Listing 2中,包含了一个使用SimpleViewEngine的 controller 。当你调用HomeController.Index() action时,它返回一个叫做Index的view。
Listing 2 – HomeController.cs (C#)
namespace Tip25.Controllers
{
[HandleError]
public class HomeController : Controller
{
public HomeController()
{
this.ViewEngine = new SimpleViewEngine();
}
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
ViewData["Message2"] = "Using a custom View Engine";
return View("Index");
}
}
}