为ASP.NET MVC应用程序创建单元测试

本教程的目的是解释如何为 ASP.NET MVC 应用程序中的控制器编写单元测试。我们将讨论如何创建三种不同类型的单元测试。您将了解如何测试控制器操作返回的视图、如何测试控制器操作返回的视图数据,以及如何测试一个控制器操作是否重定向到另一个控制器操作。

创建测试控制器

我们首先创建要测试的控制器。程序清单 1 中包含名称为 ProductController 的控制器。

程序清单 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");
          }
    }
}

HomeController 包含两个操作方法,名称为 Index() 和 Details()。两个操作方法都返回一个视图。请注意, Details() 操作接受名称为 Id 的参数。

测试控制器返回的视图

假设要测试 ProductController 是否返回正确的视图。希望确保当激活 ProductController.Details() 操作时,返回 Details 视图。程序清单 2 中的测试类包含一个单元测试,用于测试由 ProductController.Details() 操作返回的视图。

程序清单 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);
          }
    }
}

 

程序清单 2 中的类包含名称为 TestDetailsView() 的测试方法。此方法包括三行代码。第一行代码创建一个 ProductController 类的新实例。第二行代码激活控制器的 Details() 操作方法。最后一行代码检查 Details() 操作返回的是否是 Details 视图。

ViewResult.ViewName 属性代表由控制器返回的视图的名称。测试该属性时需要特别小心。控制器返回视图有两种方法。控制器可以显式地返回视图,如下所示:

public ActionResult Details(int Id)
{
    return View("Details");
}

 另外,视图的名称可以引用控制器操作的名称,如下所示:

public ActionResult Details(int Id)
{
    return View();
}

此控制器操作也返回名称为 Details 的视图。然而,视图的名称引用自操作的名称。如果想要测试视图名称,则必须显式地从控制器操作返回视图名称。

通过按 Ctrl-R,A 组合键或单击 Run All Tests in Solution 按钮(如图 1 所示),可以运行程序清单 2 中的单元测试。如果通过测试,则将看到如图 2 所示的 Test Results 窗口。

图 1:运行解决方案中的所有测试

图 2:成功!

测试控制器返回的 View Data

MVC 控制器使用 View Data 将数据传递给视图。例如,假设想要在激活 ProductController Details() 操作时显示某个产品的详细信息。在这种情况下,可以创建 Product 类的实例(在模型中定义),然后利用 View Data 将实例传递给 Details 视图。

程序清单 3 中修改后的 ProductController 包含更新的 Details() 操作,它返回 Product。

程序清单 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 类的新实例表示笔记本电脑。接下来,Product 类的实例被作为第二个参数传递给 View() 方法。

可以编写测试单元测试预期的数据是否包含在视图数据中。程序清单 4 中的单元测试用于测试表示笔记本电脑的 Product 是否在调用 ProductController Details() 操作方法时返回。

程序清单 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);
          }
     }
}

 

在程序清单 4 中,TestDetailsView() 方法通过激活 Details() 方法测试返回的 View Data。ViewData 公开为 ViewResult(通过激活 Details() 方法返回)上的一个属性。ViewData.Model 属性包含传递给视图的产品。测试只是简单地验证包含在 View Data 中的产品名称是 Laptop。

测试控制器返回的操作结果

较复杂的控制器操作可能返回不同类型的操作结果,具体取决于传递给控制器操作的参数值。控制器操作可以返回各种类型的操作结果,包括 ViewResult、RedirectToRouteResult 或 JsonResult。

例如,程序清单 5 中修改的 Details() 操作在将有效 Id 传递给操作时返回 Details 视图。如果传递无效的产品 Id(Id 的值小于 1),则将重定向到 Index() 操作。

程序清单 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);
          }
     }
}

可以使用程序清单 6 中的单元测试来测试 Details() 操作的行为。程序清单 6 中的单元测试验证当 Id 值 -1 被传递到 Details() 方法时是否重定向到 Index 视图。

程序清单 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 属性验证视图的名称。

接下来,我们研究了如何测试 View Data 的内容。学习了如何检查调用控制器操作后 View Data 中是否返回正确的产品。

最后,我们讨论了如何测试控制器操作是否返回不同类型的操作结果。学习了如何测试控制器操作是返回 ViewResult 还是 RedirectToRouteResult。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值