## 测试 ProductAppService 类 启动模板附带测试基础架构,包括**xUnit**、**Shouldly**和**NSubstitute**库。它使用*SQLite 内存*数据库来模拟数据库,并为每个测试创建一个单独的数据库。它会自动初始化数据并在测试结束时销毁测试数据。通过这种方式,测试不会相互影响,并且您的真实数据库保持不变。 下面展示在 UI 上使用应用服务之前,如何为`ProductAppService`类的`GetListAsync`方法写单元测试代码(\[*第 17 章*\]*构建自动化测试*,将探讨测试的所有细节)。 在.Application.Tests项目中创建*Products*文件夹,并在其中创建一个`ProductAppService_Tests`类: ``` using Shouldly; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Xunit; namespace ProductManagement.Products {     public class ProductAppService_Tests : ProductManagementApplicationTestBase     {         private readonly IProductAppService _productAppService;         public ProductAppService_Tests()         {             _productAppService =                 GetRequiredService<IProductAppService>();         }         /* TODO: Test methods */     } } ``` 该类继承自`ProductManagementApplicationTestBase`,它默认集成 ABP 框架和其他基础设施库,这样我们就可以直接使用内置的测试能力。另外,我们使用方法`GetRequiredService`来解决测试代码中的依赖关系,而不是构造函数注入(这在测试中是不可能的)。 现在,我们可以编写第一个测试方法。在`ProductAppService_Tests`类中添加如下代码: ``` [Fact] public async Task Should_Get_Product_List() {     //Act     var output = await _productAppService.GetListAsync(         new PagedAndSortedResultRequestDto()     );     //Assert     output.TotalCount.ShouldBe(3);     output.Items.ShouldContain(         x => x.Name.Contains("Acme Monochrome Laser Printer")     ); } ``` 该方法调用该`GetListAsync`方法并检查结果是否正确。如果您打开**测试资源管理器**窗口(在 Visual Studio 中的**查看**|**测试资源管理器**菜单下),您可以看到我们添加的测试方法。**测试资源管理器**用于显示和运行解决方案中的测试: ![](https://img.kancloud.cn/27/e7/27e771f166f57bda9a903fc0a82a4529_720x238.png) 运行测试到检查它是否按预期工作。如果方法正常工作,将在测试方法名称的左侧看到一个绿色图标。 ## 自动 API 控制器和 Swagger UI **Swagger**一款服务于开发和测试HTTP API 的的流行工具。它启动模板中已经预先装了。 设置.Web项目为启动项目,然后*按 Ctrl*+*F5*运行该项目,启动后,输入`/swagger` URL,如图所示: ![](https://img.kancloud.cn/f9/5b/f95b7e5ebade4297b7ec78ff057967a8_726x484.png) 你会看到内置的很多 API。如果向下滚动,也会看到一个**Product**接口。您可以对其进行测试以获取产品列表: ![](https://img.kancloud.cn/0c/06/0c06ff94615b82711460f342bb159743_655x213.png) >[warning] 我们没有创建*ProductController*接口。这个接口是如何出现的? 这里运用的是ABP 框架的**自动 API 控制器**功能。它会根据命名约定和配置自动将您的应用服务公开为 HTTP API(通常,我们不会手动编写控制器)。 自动 API 控制器功能将在\[*第 14 章*\] *构建 HTTP API 和实时服务* 中详细介绍。 有了 HTTP API 来获取产品列表。下一步是在客户端代码中使用此 API。 ## 动态 JavaScript 代理 通常,您通过 JavaScript 调用 HTTP API 接口。ABP 会为所有 HTTP API 动态创建客户端代理。然后,就可以使用这些动态 JavaScript 函数从客户端调用我们的 API。 再次运行[*ProductManagement.Web*](http://ProductManagement.Web)项目,并在登录页面上使用*F12*快捷键打开浏览器的**开发者控制台**,然后输入以下 JavaScript 代码: ``` productManagement.products.product.getList({}).then(function(result) {     console.log(result); }); ``` 执行此代码后,将向服务器发出请求,并将返回结果记录在**Console**选项卡中,如图所示: ![](https://img.kancloud.cn/c5/a6/c5a6bead0c97506082d30824ff752a8a_787x542.png) 我们可以看到返回的产品列表数据显示在**控制台**选项卡中。这意味着我们可以轻松地运用 JavaScript 调用服务器端 API,而无需处理低级细节。 如果您想知道JavaScript 是在哪里定义`getList`的,您可以定位到`/Abp/ServiceProxyScript`地址,查看由 ABP 框架动态创建的 JavaScript 代理函数。 在下一节,我们将创建一个**Razor 页面**并在 UI 上显示产品表。