本文演示Util應用框架開發的專案中如何編寫整合測試.
完成 Web Api 快速入門,本文將在之前生成的範例專案上講解整合測試的開發.
自動化測試對於Util應用框架的開發非常重要,它能保證基礎功能的穩定性.
對於使用 Util 開發的業務專案,自動化測試不是必須的,但掌握它可能很有用.
如果你使用 Util 開發 Web API,可能會使用 Swagger 進行測試.
將 Swagger 提供給前端人員是合適的,但後端人員使用它卻不夠省力.
原因很簡單,使用 Swagger 測試 API,需要設定一堆引數,這些引數無法儲存,每次執行都需要設定.
使用 .Net 自動化測試會更加方便,並且現在開發整合測試的成本很低.
專業測試的分類非常細,下面簡要討論自動化功能測試.
這裡粗略的對自動化功能測試概括為兩類:
單元測試
整合測試
修改任何一行業務程式碼,都有可能影響之前的邏輯.
自動化測試基於對業務功能的預期反應,如果預期未發生變化,但你的程式碼邏輯出現變化,就能幫你攔截這個錯誤.
除了開發自動化測試本身的成本以外,更大的成本在於維護.
每當需求變更,需要刪除已經過時的測試,開發新的測試,修改之前的測試以符合當前預期.
自動化測試的語法非常簡單,但並不是掌握了測試語法就能編寫出有效的測試.
編寫單元測試需要開發人員有一定抽象思維,能夠抽象和隔離依賴,還需要了解一些單元測試技巧.
不要在公司全面推行單元測試,容易變成形式主義,僅讓團隊核心骨幹對高價值業務模組編寫單元測試.
整合測試則要簡單得多,只要懂得測試語法就可以編寫.
整合測試由於直接存取外部依賴,執行緩慢,而且任何環節變更都可能導致測試失敗,所以不宜大量編寫.
如果你僅負責編寫 Web API ,手頭沒有現成的UI進行測試,編寫整合測試比使用 Swagger 省力.
如果你沒有打算持續維護這些測試,不要編寫它們,那隻會浪費時間.
如果你的團隊精力有限,無法維護大量的測試,可以僅對高業務價值的模組編寫測試.
測試框架
模擬框架
資料偽造框架
單元測試用於測試複雜的業務邏輯,由於快速入門Demo僅包含簡單CRUD操作,無法演示單元測試的用法.
下面介紹在Util專案中如何開發整合測試.
開啟範例專案解決方案 Demo.sln,檢視 test 子目錄,它包含4個測試專案.
生成的測試專案已經將環境設定完成,你可以直接開始編寫測試.
Demo.Domain.Tests 是領域層的單元測試專案,如果你不需要編寫單元測試,直接刪掉它.
其它三個專案用於整合測試,下面分別介紹.
Demo.Data.SqlServer.Tests 是資料存取層 Sql Server 整合測試專案.
如果支援多種資料庫,則每種資料庫應包含一個資料存取層整合測試專案.
資料存取層測試的重點是倉儲.
開啟 StudentRepositoryTest 學生倉儲測試類.
在 StudentRepositoryTest 的構造方法中注入了依賴介面 IDemoUnitOfWork 和 IStudentRepository.
Util 程式碼生成模板預設會建立 TestAddAsync 方法,它用於測試新增實體.
該測試使用偽資料生成框架建立學生實體,並通過倉儲儲存到資料庫.
不宜編寫過多的CRUD整合測試,通常保留一兩個即可.
它們的作用不是測試邏輯,而是迅速識別開發環境是否通暢.
特別是當你升級框架或類庫時,有幾個簡單的整合測試非常有用.
開啟 appsettings.Development.json 組態檔,檢查連線字串是否正確.
{
"ConnectionStrings": {
"connection": "Server=.;Database=Demo.Data.Test;uid=sa;pwd=Pass@word;TrustServerCertificate=true"
}
}
Demo範例的資料存取層測試資料庫名為 Demo.Data.Test ,執行測試時, EntityFrameworkCore 會自動建立和刪除測試資料庫,非常方便.
右鍵單擊 TestAddAsync 方法,彈出選單選擇 執行測試.
彈出 測試資源管理器 視窗,並自動執行測試.
如果你安裝了Resharper, VS中的測試方法會在左側顯示測試圖示,如下圖所示.
點選 Run 按鈕,執行測試.
應用層整合測試包含 Demo.Application.Tests 和 Demo.Api.Tests 兩個測試專案.
Demo.Application.Tests 側重於測試應用服務,並且沒有Asp.Net Core相關環境干擾.
對於普通專案,大多業務邏輯會寫到應用服務中, 所以它是比較理想的測試場所.
如果你不想維護太多測試專案,那麼僅保留應用服務整合測試即可.
開啟 StudentServiceTest 測試類,程式碼生成模板預設也建立了一個 TestCreateAsync 測試方法.
/// <summary>
/// 學生服務測試
/// </summary>
public class StudentServiceTest {
/// <summary>
/// 學生服務
/// </summary>
private readonly IStudentService _service;
/// <summary>
/// 測試初始化
/// </summary>
public StudentServiceTest( IStudentService service ) {
_service = service;
}
/// <summary>
/// 測試建立
/// </summary>
[Fact]
public async Task TestCreateAsync() {
//建立
var dto = StudentDtoFakeService.GetStudentDto();
var id = await _service.CreateAsync( dto );
//驗證
var result = await _service.GetByIdAsync( id );
Assert.NotNull( result );
Assert.Equal( id, result.Id );
}
}
StudentServiceTest 從構造方法注入了 IStudentService 應用服務介面.
使用偽資料生成框架建立DTO,並呼叫服務儲存資料.
Demo.Api.Tests 用於測試 Web Api控制器,它的測試環境要複雜一些.
開啟 StudentControllerTest 測試類.
/// <summary>
/// 學生控制器測試
/// </summary>
public class StudentControllerTest : TestBase {
/// <summary>
/// 輸出工具
/// </summary>
private readonly ITestOutputHelper _testOutputHelper;
/// <summary>
/// 測試初始化
/// </summary>
public StudentControllerTest( ITestOutputHelperAccessor testOutputHelperAccessor,IHttpClient client ) : base( client ){
_testOutputHelper = testOutputHelperAccessor.Output;
}
/// <summary>
/// 測試建立
/// </summary>
[Fact]
public async Task TestCreateAsync() {
//服務地址
var url = "/api/student";
//建立實體
var dto = StudentDtoFakeService.GetStudentDto();
var result = await PostAsync<StudentDto>( url, dto );
//驗證
Assert.Equal( StateCode.Ok, result.Code );
Assert.NotEmpty( result.Data.Id );
_testOutputHelper.WriteLine( Json.ToJson( result ) );
}
}
Web Api的測試需要傳送請求給控制器,並接收響應結果,所以需要一個Http使用者端.
StudentControllerTest 構造方法注入 Util Http使用者端介面,將介面傳遞給 TestBase 基礎類別.
TestBase 進一步封裝對 GET, POST ,PUT ,DELETE 操作請求,以簡化測試的編寫.
預設生成的 TestCreateAsync 方法,使用偽資料生成框架建立DTO, 並使用 Post 請求指定 Url.
Web Api 控制器返回 Util 約定的特定訊息.
對於開發 Web Api, 該整合測試能更好的反映與前端的互動.
執行 Web Api整合測試,如下所示.