作者: Tom FitzMacken
本指南和应用程序演示如何为 Web API 2 应用程序创建简单的单元测试。 本教程演示如何在解决方案中包含单元测试项目,并编写测试方法来检查控制器方法返回的值。
本教程假定你熟悉 ASP.NET Web API 的基本概念。 有关介绍性教程,请参阅 ASP.NET Web API 2 入门。
本主题中的单元测试有意仅限于简单的数据方案。 有关更高级的数据方案的单元测试,请参阅 单元测试 ASP.NET Web API 2 时模拟实体框架。
本教程中使用的软件版本
- Visual Studio 2017
- Web API 2
本主题内容
本主题包含以下各节:
先决条件
Visual Studio 2017 社区版、专业版或企业版
下载代码
下载 已完成的项目。 可下载的项目包括本主题的单元测试代码,以及 单元测试 ASP.NET Web API 主题时的模拟实体框架 。
使用单元测试项目创建应用程序
可以在创建应用程序时创建单元测试项目,也可以向现有应用程序添加单元测试项目。 本教程演示了用于创建单元测试项目的这两种方法。 若要遵循本教程,可以使用任一方法。
创建应用程序时添加单元测试项目
创建名为 StoreApp 的新 ASP.NET Web 应用程序。
在“新建 ASP.NET 项目”窗口中,选择 “空 ”模板,并为 Web API 添加文件夹和核心引用。 选择 “添加单元测试 ”选项。 单元测试项目自动命名为 StoreApp.Tests。 可以保留此名称。
创建应用程序后,会看到它包含两个项目。
将单元测试项目添加到现有应用程序
如果在创建应用程序时未创建单元测试项目,可以随时添加一个。 例如,假设已有一个名为 StoreApp 的应用程序,并且想要添加单元测试。 若要添加单元测试项目,请右键单击解决方案,然后选择 “添加 ”和“ 新建项目”。
在左窗格中选择“ 测试 ”,然后为项目类型选择 “单元测试项目 ”。 将项目 命名为 StoreApp.Tests。
你将在解决方案中看到单元测试项目。
在单元测试项目中,向原始项目添加项目引用。
设置 Web API 2 应用程序
在 StoreApp 项目中,将类文件添加到名为Product.cs的 Models 文件夹中。 将文件的内容替换为以下代码。
using System;
namespace StoreApp.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
生成解决方案。
右键单击“控制器”文件夹,然后选择“ 添加 ”和“ 新建基架项”。 选择 “Web API 2 控制器 - 空”。
将控制器名称设置为 SimpleProductController,然后单击“ 添加”。
将现有代码替换为以下代码。 为了简化此示例,数据存储在列表中,而不是数据库。 此类定义的列表代表生产数据。 请注意,控制器包含一个构造函数,该构造函数采用 Product 对象的列表作为参数。 此构造函数允许您在进行单元测试时传递测试数据。 控制器还包括两种 异步 方法,用于演示单元测试异步方法。 这些异步方法通过调用 Task.FromResult 来最大程度地减少多余的代码,但通常这些方法将包括资源密集型操作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using StoreApp.Models;
namespace StoreApp.Controllers
{
public class SimpleProductController : ApiController
{
List<Product> products = new List<Product>();
public SimpleProductController() { }
public SimpleProductController(List<Product> products)
{
this.products = products;
}
public IEnumerable<Product> GetAllProducts()
{
return products;
}
public async Task<IEnumerable<Product>> GetAllProductsAsync()
{
return await Task.FromResult(GetAllProducts());
}
public IHttpActionResult GetProduct(int id)
{
var product = products.FirstOrDefault((p) => p.Id == id);
if (product == null)
{
return NotFound();
}
return Ok(product);
}
public async Task<IHttpActionResult> GetProductAsync(int id)
{
return await Task.FromResult(GetProduct(id));
}
}
}
GetProduct 方法返回 IHttpActionResult 接口的实例。 IHttpActionResult 是 Web API 2 中的新功能之一,它简化了单元测试开发。 在 System.Web.Http.Results 命名空间中找到实现 IHttpActionResult 接口的类。 这些类表示来自操作请求的可能响应,它们对应于 HTTP 状态代码。
生成解决方案。
您现在已准备好启动测试项目。
在测试项目中安装 NuGet 包
使用空模板创建应用程序时,单元测试项目(StoreApp.Tests)不包含任何已安装的 NuGet 包。 其他模板(如 Web API 模板)在单元测试项目中包括一些 NuGet 包。 在本教程中,必须将 Microsoft ASP.NET Web API 2 核心包包含在测试项目中。
右键单击 StoreApp.Tests 项目,然后选择“ 管理 NuGet 包”。 必须选择 StoreApp.Tests 项目才能将包添加到该项目。
查找并安装 Microsoft ASP.NET Web API 2 核心包。
关闭“管理 NuGet 包”窗口。
创建测试
默认情况下,测试项目包含一个名为UnitTest1.cs的空测试文件。 此文件显示用于创建测试方法的属性。 对于单元测试,可以使用此文件或创建自己的文件。
在本教程中,你将创建自己的测试类。 可以删除UnitTest1.cs文件。 添加名为 TestSimpleProductController.cs的类,并将代码替换为以下代码。
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http.Results;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StoreApp.Controllers;
using StoreApp.Models;
namespace StoreApp.Tests
{
[TestClass]
public class TestSimpleProductController
{
[TestMethod]
public void GetAllProducts_ShouldReturnAllProducts()
{
var testProducts = GetTestProducts();
var controller = new SimpleProductController(testProducts);
var result = controller.GetAllProducts() as List<Product>;
Assert.AreEqual(testProducts.Count, result.Count);
}
[TestMethod]
public async Task GetAllProductsAsync_ShouldReturnAllProducts()
{
var testProducts = GetTestProducts();
var controller = new SimpleProductController(testProducts);
var result = await controller.GetAllProductsAsync() as List<Product>;
Assert.AreEqual(testProducts.Count, result.Count);
}
[TestMethod]
public void GetProduct_ShouldReturnCorrectProduct()
{
var testProducts = GetTestProducts();
var controller = new SimpleProductController(testProducts);
var result = controller.GetProduct(4) as OkNegotiatedContentResult<Product>;
Assert.IsNotNull(result);
Assert.AreEqual(testProducts[3].Name, result.Content.Name);
}
[TestMethod]
public async Task GetProductAsync_ShouldReturnCorrectProduct()
{
var testProducts = GetTestProducts();
var controller = new SimpleProductController(testProducts);
var result = await controller.GetProductAsync(4) as OkNegotiatedContentResult<Product>;
Assert.IsNotNull(result);
Assert.AreEqual(testProducts[3].Name, result.Content.Name);
}
[TestMethod]
public void GetProduct_ShouldNotFindProduct()
{
var controller = new SimpleProductController(GetTestProducts());
var result = controller.GetProduct(999);
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
}
private List<Product> GetTestProducts()
{
var testProducts = new List<Product>();
testProducts.Add(new Product { Id = 1, Name = "Demo1", Price = 1 });
testProducts.Add(new Product { Id = 2, Name = "Demo2", Price = 3.75M });
testProducts.Add(new Product { Id = 3, Name = "Demo3", Price = 16.99M });
testProducts.Add(new Product { Id = 4, Name = "Demo4", Price = 11.00M });
return testProducts;
}
}
}
运行测试
现在可以运行测试了。 将测试使用 TestMethod 属性标记的所有方法。 从 “测试 ”菜单项运行测试。
打开 “测试资源管理器” 窗口,并注意测试结果。
总结
你已完成本教程。 本教程中的数据是有意简化的,以专注于单元测试条件。 有关更高级的数据方案的单元测试,请参阅 单元测试 ASP.NET Web API 2 时模拟实体框架。