ASP.NET MVC 端到端集成测试






4.50/5 (3投票s)
当控制器被视为普通类时,ASP.NET MVC 应用程序具有很强的可测试性,但这样会失去与模型验证、筛选器、方法选择器等功能的集成。
引言
本文档描述了 Xania.AspNet.Simulator
库如何帮助进行 MVC 应用程序的集成测试,使其变得令人愉快。无需再编写复杂的样板代码来测试你的控制器操作,同时提供对操作筛选器、模型验证、操作选择器等功能的支持。
背景
我一直在多个不同的 ASP.NET MVC 应用程序上工作,尽管有良好的初步意图,但这些项目中的大多数都没有考虑到可测试性。在我的最后一个项目中,我被明确要求通过重构代码来提高代码质量,简而言之,就是用服务替换 static
类,删除重复代码块,将方法拆分为更小的、职责更明确的片段等等。
我发现自己身处一种什么都不如想象中的情况。代码库远非“自文档化”,甚至 ‘Login
’ 操作也远不止简单地登录用户。
解决这个问题的方法是从顶层开始,从操作层面入手,在那里我可以控制请求、响应、标头、会话、cookie、路由、筛选器、选择器、ViewData 和 ModelState,并在开始重构代码之前在该层面编写测试。不幸的是,ASP.NET MVC 框架默认情况下不支持一种简单的方法来编写支持所有这些功能的控制器操作测试。因此,我开始编写代码,将所有这些功能打包到一个易于使用的包中,名为 Xania.AspNet.Simulator。
Using the Code
以以下帐户控制器实现为例
[Authorize]
public class AccountController : System.Web.Mvc.Controller
{
public AccountController()
{
}
//
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = // find user
if (user != null)
{
return Redirect(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/LogOff
[HttpPost]
public ActionResult LogOff()
{
// sign out user
return RedirectToAction("Index", "Home");
}
}
让我们开始编写集成测试。
- 第一个
Login
操作可供匿名用户访问,并且设置了ViewBag.ReturnUrl
。[Test] public void GetLoginTest() { // arrange var action = new AccountController().Action(c => c.Login("[returnUrl]")); // act var result = action.Execute(); // assert Assert.IsInstanceOf<ViewResult>(result.ActionResult); Assert.AreEqual("[returnUrl]", result.ViewBag.ReturnUrl); }
- 第二个
Login
操作可供匿名用户通过 post 方法访问,并且需要LoginViewModel
有效。[Test] public void InvalidPostLoginTest() { // arrange, when http method is GET var action = new AccountController().Action (c => c.Login(null), "GET" /* is default */); // assert Assert.IsNull(action); // not found } [Test] public void PostLoginTest() { // arrange var model = new LoginViewModel { UserName = "user1", Password = "passw1" }; var action = new AccountController().Action(c => c.Login(model), "POST"); // act var result = action.Execute(); // assert, assume user exists Assert.IsInstanceOf<RedirectResult>(result.ActionResult); Assert.AreEqual("[returnUrl]", result.ViewBag.ReturnUrl); }
logoff
操作仅可供授权用户通过post
方法访问。[Test] public void PostLogOffTest() { // arrange var action = new AccountController().Action(c => c.LogOff(), "POST"); // act var result = action.Authenticate("user1", new string[0]).Execute(); // assert Assert.IsInstanceOf<RedirectToRouteResult>(result.ActionResult); } [Test] public void PostLogOffUnauthenticatedTest() { // arrange var action = new AccountController().Action(c => c.LogOff(), "POST"); // act, but don't authenticate var result = action.Execute(); // assert Assert.IsInstanceOf<HttpUnauthorizedResult>(result.ActionResult); }
关注点
代码库在 github 上
并且可以在 NuGet 上找到一个发行版,ID 为 Xania.AspNet.Simulator
。