## 測試 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 中的**查看**|**測試資源管理器**菜單下),您可以看到我們添加的測試方法。**測試資源管理器**用于顯示和運行解決方案中的測試:

運行測試到檢查它是否按預期工作。如果方法正常工作,將在測試方法名稱的左側看到一個綠色圖標。
## 自動 API 控制器和 Swagger UI
**Swagger**一款服務于開發和測試HTTP API 的的流行工具。它啟動模板中已經預先裝了。
設置.Web項目為啟動項目,然后*按 Ctrl*+*F5*運行該項目,啟動后,輸入`/swagger` URL,如圖所示:

你會看到內置的很多 API。如果向下滾動,也會看到一個**Product**接口。您可以對其進行測試以獲取產品列表:

>[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**選項卡中,如圖所示:

我們可以看到返回的產品列表數據顯示在**控制臺**選項卡中。這意味著我們可以輕松地運用 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測試基礎設施
- 構建單元測試
- 構建集成測試