这篇文章主要演示如何为ASP.NET MVC应用程序创建单元测试。这里我们讨论了如何建三类单元测试
测试控制器返回特定的视图
测试控制器返回特定的View Data
测试控帽器返回特定的Action Result
一、创建要测试的控制器
我们把要测试的控制器命名为ProductController,代码如下:
Listing 1 – ProductController.cs
using System;
using System.Web.Mvc;
namespace Store.Controllers
{
public class ProductController : Controller
{
public ActionResult Index()
{
// Add action logic here
throw new NotImplementedException();
}
public ActionResult Details(int Id)
{
return View("Details");
}
}
}
ProductController控制器包含两个控制动作Index()和Details()。两个控制器都返回视图,另外Details()动作接收一个名子为Id的形参
二、测试控制器返回的视图。(原创:灰灰虫的家 http://hi.baidu.com/grayworm)
假设我们要测试ProductController是否返回正确的视图,确保ProductController.Details()动被能够被调用,并返回Details视图。下面的代码包含了测试ProductController.Details()动作的单元测试。
Listing 2 – ProductControllerTest.cs
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Store.Controllers;
namespace StoreTests.Controllers
{
[TestClass]
public class ProductControllerTest
{
[TestMethod]
public void TestDetailsView()
{
var controller = new ProductController();
var result = controller.Details(2) as ViewResult;
Assert.AreEqual("Details", result.ViewName);
}
}
}
在上面的代码中我们定义了一个TestDetailsView()方法,这个方法包含了三行代码,第一行代码是创建ProductController类的实例。第二行代码调用控制器的Details()动作方法。最后一行代码检查Details()动作是否返回Details视图。
ViewResult.ViewName属性表示由控制层返回视图的名称。控制器有两种返回视图的方法:
1.控制器动作以显式地返回视图名称
public ActionResult Details(int Id) { return View("Details"); }
2.控制器动作返回视图的默认名称是控制器动作名
public ActionResult Details(int Id) { return View(); }
但如果我们要测试返回视图的名称,那我们必须在控制器动作中显式返回视图名称。
我们可以按Ctrl+R,A来运行单元测试,也可以点击Run All Tests in Solution按钮,如下图所示,如果单元测试运行通过,我们会在Test Results窗口中看到测试结果,如下图所示
《图1》
《图2》
三、测试控制器返回的ViewData(原创:灰灰虫的家 http://hi.baidu.com/grayworm)
MVC控制器通过ViewData向视图层返回数据。例如,假设我们想在调用ProductController.Details()动作后,显示特定产品的详细信息。那我们可以在Details()动作中创建Product实例,并使用ViewData把它传递给Details视图
Details()动作代码如下所示,返回一条产品信息。
Listing 3 – ProductController.cs
using System;
using System.Web.Mvc;
namespace Store.Controllers
{
public class ProductController : Controller
{
public ActionResult Index()
{
// Add action logic here
throw new NotImplementedException();
}
public ActionResult Details(int Id)
{
var product = new Product(Id, "Laptop");
return View("Details", product);
}
}
}
首先,在Details动作中我们创建一个Product的实例,该实例是一台laptop计算机,然后我们把它传入View()方法中。
我们可以编写单元测试,以检查在Details()返回的ViewData数据中是否包含预期的数据。下面的代码是来测试ProductController.Details()动作是否返回一个laptop计算机的产品实例。
Listing 4 – ProductControllerTest.cs
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Store.Controllers;
namespace StoreTests.Controllers
{
[TestClass]
public class ProductControllerTest
{
[TestMethod]
public void TestDetailsViewData()
{
var controller = new ProductController();
var result = controller.Details(2) as ViewResult;
var product = (Product) result.ViewData.Model;
Assert.AreEqual("Laptop", product.Name);
}
}
}
在上面的代码中,TestDetailsView()方法用来测试Details()控制动作返回的ViewData。该ViewData是Details()动作以ViewResult的属性形式出现的。ViewDataModel包含传递给视图的产品。该测试就是检查控制器动作返回的ViewData中产品的名子是否是LapTop。
四、测试控制器返回的Action Result(原创:灰灰虫的家 http://hi.baidu.com/grayworm)
复杂的控制器动作往往根据传入的参数不同而返回不同类型的Action Result。控制器动作可以返回各种Action Result。如ViewResult、RedirectToRouteResult和JsonResult。
例如下面的代码,Details动作接收一个Id参数,当我们传递合法的Id(Id>=1)进去的时候,Details()动作返回Details视图,如果传递的Id不合法(Id<1)时,Details()动作跳转到Index()动作。
Listing 5 – ProductController.cs
using System;
using System.Web.Mvc;
namespace Store.Controllers
{
public class ProductController : Controller
{
public ActionResult Index()
{
// Add action logic here
throw new NotImplementedException();
}
public ActionResult Details(int Id)
{
if (Id < 1)
return RedirectToAction("Index");
var product = new Product(Id, "Laptop");
return View("Details", product);
}
}
}
我们可以编写下面的测试代码来测试Details()动作的行为。下面的测试代码主要来检验当我们传递-1给Details()动作时,能否跳转到Index视图。
Listing 6 – ProductControllerTest.cs
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Store.Controllers;
namespace StoreTests.Controllers
{
[TestClass]
public class ProductControllerTest
{
[TestMethod]
public void TestDetailsRedirect()
{
var controller = new ProductController();
var result = (RedirectToRouteResult) controller.Details(-1);
Assert.AreEqual("Index", result.Values["action"]);
}
}
}
当我们在控制器动作中调用RedirectToAction()方法时,控制器动作返回RedirectToRouteResult。测试代码检查RedirectToRouteResult是否要把用户重定向到Index动作上。
总结
在这篇文章中我们学习如何为MVC控制器动作创建单元测试。
首先,我们学习检验控制器动作是否返回正确的视图。使用ViewResult.ViewName属笥来验证返回的视图名称
然后,我们学习如何检验返回的ViewData的内容。这里我们检验控制器动作是否在ViewData中返回正确的产品信息。
最后,我们讨论了如何测试控制器是否返回多个ActionResult。这里我们测试了控制器返回的是ViewResult还是RedirectToRouteResult。