## 测试 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 上显示产品表。
- 前言
- 第一部分
- 第1章 现代软件开发和 ABP 框架
- 企业级 Web 开发的挑战
- ABP框架的能力清单
- 第2章 ABP框架入门
- 安装 ABP CLI
- 创建新解决方案
- 运行解决方案
- 探索预构建模块
- 第3章 逐步开发开发ABP应用
- 创建解决方案
- 定义领域对象
- EFCore和数据库映射
- 定义应用服务
- 测试产品
- 产品列表
- 创建产品
- 编辑产品
- 删除产品
- 第4章 探索 EventHub解决方案
- 应用介绍
- 架构探索
- 方案运行
- 第二部分
- 第5章 探索ABP基础架构
- 了解模块化
- 使用依赖注入系统
- 配置应用程序
- 实现选项模式
- 日志系统
- 第6章 数据访问基础架构
- 定义实体
- 定义仓储库
- EF Core集成
- 了解 UoW
- 第7章 探索横切关注点
- 认证授权
- 用户验证
- 异常处理
- 第8章 体验 ABP 的功能和服务
- 获取当前用户
- 使用数据过滤
- 控制审计日志
- 缓存数据
- 本地化用户界面
- 第三部分
- 第9章 理解领域驱动设计
- 介绍 DDD
- 构建基于 DDD 的 解决方案
- 处理多个应用程序
- 了解执行流程
- DDD的通用原则
- 第10章 领域层 Domain
- 领域事件案例分析
- 聚合和实体的设计原则和实践
- 实现领域服务
- 落地存储库
- 构建规约(Specification)
- 领域事件
- 第11章 应用层 Application
- 落地应用服务
- 设计 DTO
- 理解各层的职责
- 第四部分
- 第12章 MVC/Razor 页面
- 主题系统
- 绑定和压缩
- 导航菜单
- Bootstrap标签助手
- 创建表单并验证
- 使用模态窗口
- 使用JS API
- 调用HTTP API
- 第13章 Blazor WebAssembly UI
- 什么是Blazor
- ABP Blazor UI
- 验证用户身份
- 理解主题系统
- 使用菜单
- 使用基本服务
- 使用UI服务
- 消费HTTP API
- 使用全局脚本和样式
- 第14章 HTTP API 和实时服务
- 构建HTTP API
- 使用HTTP API
- 使用SignalR
- 第五部分
- 第15章 落地模块化
- 理解模块化
- 构建支付模块
- 安装模块
- 第16章 实现多租户
- 理解多租户
- 多租户基础设施
- 使用功能系统
- 何时使用多租户
- 第17章 构建自动化测试
- 了解ABP测试基础设施
- 构建单元测试
- 构建集成测试