在开发ASP.NET MVC应用程序时,单元测试是开发过程中不可或缺的一部分。然而,有些情况下,单独测试代码片段(例如控制器)可能相对容易,但对于其他部分(如模型绑定器)则可能较为困难。此外,对于安全性相关问题,单独测试单个代码片段可能没有太大意义。在这种情况下,需要进行某种形式的集成测试。在ASP.NET MVC的上下文中,通常意味着需要使用浏览器自动化框架,如SeleniumRC、WatiN或轻量级测试自动化框架等。这些工具可以自动化真实的浏览器实例,并要求被测试的网站托管在Web服务器上。因此,这种测试方式需要相当多的资源,并引入了自身的一系列问题和错误可能性。
为了使这些测试更加开发人员友好、资源需求更低且错误更少,偶然发现了一篇博客文章:。它介绍了一个框架,用于在不需要任何浏览器或服务器的情况下对ASP.NET MVC应用程序进行集成测试,但仍在真实的(非模拟的)ASP.NET运行时环境中运行。可以参考上述文章,了解更多关于所谓的MvcIntegrationTestFramework的理由、各种可能性和技术细节,以及如何使用它的更多示例。
为了将框架更紧密地集成到Gallio/MbUnit上下文中,发现编写一个自定义测试夹具的基类非常有用,它基本上是MvcIntegrationTestFramework的包装器。因此,可以像这样对MVC应用程序编写测试(记住:无需浏览器或服务器或其他任何东西,它就是可以工作...):
[Test]
public void SimulateRequestToRootUrl()
{
RunSession(session =>
{
// 请求根URL
RequestResult result = session.ProcessRequest("~/");
// 关于创建请求的控制器的断言...
var controller = result.ActionExecutedContext.Controller as HomeController;
Assert.IsNotNull(controller);
// 关于ActionResult的断言...
var viewResult = (ViewResult)result.ActionExecutedContext.Result;
Assert.AreEqual("Index", viewResult.ViewName);
Assert.AreEqual("Welcome to ASP.NET MVC!", viewResult.ViewData["Message"]);
// 关于渲染的HTML的断言...
Assert.IsTrue(result.ResponseText.Contains("
...或者,测试登录/防伪造机制,如下所示:
[Test]
public void TryingToAccessSecuredPageWithoutLoggingInIsBeingRedirected()
{
RunSession(session =>
{
RequestResult result = session.ProcessRequest(SecuredUrl);
Assert.IsTrue(result.Response.IsRequestBeingRedirected);
});
}
[Test]
public void CanAccessSecuredPageAfterLoggingIn()
{
RunSession(session =>
{
// 首先重定向到登录页面并获取防伪造令牌
string loginRedirectUrl = session.ProcessRequest(SecuredUrl).Response.RedirectLocation;
string loginPageResponseText = session.ProcessRequest(loginRedirectUrl).ResponseText;
string antiForgeryToken = MvcUtils.ExtractAntiForgeryToken(loginPageResponseText);
// 用用户凭据和验证令牌提交登录表单
var formData = new NameValueCollection
{
{"username", "thomas"},
{"password", "blah"},
{"__RequestVerificationToken", antiForgeryToken}
};
session.ProcessRequest(loginRedirectUrl, HttpVerbs.Post, formData);
// 现在,登录后再次访问受保护的页面...
RequestResult result = session.ProcessRequest(SecuredUrl);
// ...这次应该一切正常。
Assert.AreEqual("Hello thomas!", result.ResponseText);
});
}
上述代码是自解释的,认为。要使其工作,自定义测试夹具必须派生自MvcIntegrationFixture基类,它只需要在构造函数中提供Web应用程序的基目录:
public class MvcIntegrationFixture : MvcIntegrationFixtureBase
{
public MvcIntegrationFixture()
: base(Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + "\\..\\..\\..\\MvcIntegrationFixtureDemo"))
{
// 测试放在这里...
}
}