在 ASP.NET Core Blazor 中測試 Razor 元件
注意
這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本。
作者:Egil Hansen
測試 Razor 元件是發行穩定且可維護 Blazor 應用程式的重要層面。
若要測試 Razor 元件,受測元件 (CUT) 為:
- 使用測試的相關輸入轉譯。
- 視所執行的測試類型而定,可能受限於互動或修改。 例如,可以觸發事件處理常式,例如按鈕的
onclick
事件。 - 檢查是否有預期的值。 當一或多個受檢的值符合測試的預期值時,測試就會通過。
測試方法
測試 Razor 元件的兩種常見方法為端對端 (E2E) 測試和單元測試:
單元測試:單元測試是以提供下列各項的單元測試程式庫撰寫:
- 元件轉譯。
- 檢查元件輸出和狀態。
- 觸發事件處理常式和生命週期方法。
- 元件行為正確的判斷提示。
bUnit 是可啟用 Razor 元件單元測試的程式庫範例。
E2E 測試:測試執行器會執行包含 CUT 的 Blazor 應用程式,並將瀏覽器執行個體自動化。 測試工具會透過瀏覽器檢查並與 CUT 互動。 適用於 .NET 的 Playwright 是 E2E 測試架構的範例,可與 Blazor 應用程式搭配使用。
在單元測試中,只涉及 Razor 元件 (Razor/C#)。 必須模擬外部相依性,例如服務和 JS Interop。 在 E2E 測試中,Razor 元件及其所有輔助基礎結構都是測試的一部分,包括 CSS、JS、DOM 和瀏覽器 API。
「測試範圍」描述測試的範圍有多廣泛。 測試範圍通常會影響測試的速度。 單元測試會在應用程式的子系統子集上執行,且通常會以毫秒為單位執行。 E2E 測試會測試應用程式子系統的廣泛群組,可能需要幾秒鐘的時間才能完成。
單元測試也提供 CUT 執行個體的存取權,允許檢查和驗證元件的內部狀態。 這在 E2E 測試中通常不可能。
就元件的環境而言,E2E 測試必須確定在驗證開始之前,已達到預期的環境狀態。 否則,無法預測結果。 在單元測試中,CUT 轉譯和測試生命週期更加整合,可改善測試穩定性。
E2E 測試牽涉到啟動多個處理序、網路和磁碟 I/O,以及通常會導致測試可靠性不佳的其他子系統活動。 單元測試通常可避免這幾種問題。
下表摘要說明這兩種測試方法之間的差異。
功能 | 單元測試 | E2E 測試 |
---|---|---|
測試範圍 | 僅限 Razor 元件 (Razor/C#) | 搭配 CSS/JS 的 Razor 元件 (Razor/C#) |
測試執行時間 | 毫秒 | 秒 |
存取元件執行個體 | 是 | No |
對環境敏感 | No | Yes |
可靠性 | 更加可靠 | 較不可靠 |
選擇最適當的測試方法
選擇要執行的測試類型時,請考量情節。 下表描述一些考量。
案例 | 建議的方法 | 備註 |
---|---|---|
不含 JS Interop 邏輯的元件 | 單元測試 | 當 Razor 元件中沒有 JS Interop 的相依性時,不需存取 JS 或 DOM API 即可測試該元件。 在此情節中,選擇單元測試沒有任何缺點。 |
具有簡單 JS Interop 邏輯的元件 | 單元測試 | 元件通常會透過 JS Interop 查詢 DOM 或觸發動畫。 在此情節中,通常慣用單元測試,因為透過 IJSRuntime 介面模擬 JS 互動相當簡單。 |
相依於複雜 JS 程式碼的元件 | 單元測試和個別 JS 測試 | 如果元件使用 JS Interop 呼叫大型或複雜的 JS 程式庫,但 Razor 元件與 JS 程式庫之間的互動很簡單,則最佳方法可能是將元件和 JS 程式庫或程式碼視為兩個不同的部分並各自分開測試。 使用單元測試程式庫測試 Razor 元件,並使用 JS 測試程式庫測試 JS。 |
具有的邏輯取決於瀏覽器 DOM 的 JS 操作的元件 | E2E 測試 | 當元件的功能相依於 JS 及其 DOM 操作時,請在 E2E 測試中一起確認 JS 和 Blazor 程式碼。 這是 Blazor 架構開發人員搭配 Blazor 瀏覽器轉譯邏輯採用的方法,其具有緊密結合的 C# 和 JS 程式碼。 C# 和 JS 程式碼必須一起運作,才能在瀏覽器中正確轉譯 Razor 元件。 |
相依於具有難以模擬相依性的第三方類別庫的元件 | E2E 測試 | 當元件的功能相依於具有難以模擬相依性的第三方類別庫 (例如 JS Interop) 時,E2E 測試可能是測試元件的唯一選項。 |
使用 bUnit 測試元件
Blazor 沒有官方的 Microsoft 測試架構,但社群驅動的專案 bUnit 提供便利的方法來單元測試 Razor 元件。
注意
bUnit 是第三方測試程式庫,Microsoft 不提供支援或維護。
bUnit 可搭配一般用途的測試架構運作,例如 MSTest、NUnit 和 xUnit。 這些測試架構讓 bUnit 測試的外觀和操作如同一般單元測試。 與一般用途測試架構整合的 bUnit 測試通常使用以下項目執行:
- Visual Studio 的測試總管。
dotnet test
命令殼層中的 CLI 命令。- 自動化 DevOps 測試管線。
注意
不同測試架構的測試概念和測試實作彼此相似但並不相同。 如需指引,請參閱測試架構的文件。
以下示範在以 Blazor 專案範本為基礎的應用程式中,Counter
元件上的 bUnit 測試結構。 Counter
元件會根據在頁面中選取按鈕的使用者來顯示和遞增計數器:
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
下列 bUnit 測試會驗證當已選取按鈕時,CUT 的計數器是否正確遞增:
@code {
[Fact]
public void CounterShouldIncrementWhenClicked()
{
// Arrange
using var ctx = new TestContext();
var cut = ctx.Render(@<Counter />);
var paraElm = cut.Find("p");
// Act
cut.Find("button").Click();
// Assert
var paraElmText = paraElm.TextContent;
paraElm.MarkupMatches("Current count: 1");
}
}
測試也可以寫入 C# 類別檔案中:
public class CounterTests
{
[Fact]
public void CounterShouldIncrementWhenClicked()
{
// Arrange
using var ctx = new TestContext();
var cut = ctx.RenderComponent<Counter>();
var paraElm = cut.Find("p");
// Act
cut.Find("button").Click();
// Assert
var paraElmText = paraElm.TextContent;
paraElmText.MarkupMatches("Current count: 1");
}
}
下列動作會在測試的每個步驟進行:
Arrange:
Counter
元件會使用 bUnit 的TestContext
來轉譯。 CUT 的段落元素 (<p>
) 已找到並指派給paraElm
。 在 Razor 語法中,元件可以當做 RenderFragment 傳遞至 bUnit。Act:按鈕的元素 (
<button>
) 是藉由呼叫Click
來尋找並選取,該元素應使計數器遞增並更新段落標籤 (<p>
) 的內容。 段落元素文字內容可藉由呼叫TextContent
取得。Assert:在文字內容上呼叫
MarkupMatches
,以確認其是否符合預期的字串,也就是Current count: 1
。
注意
MarkupMatches
判斷提示與一般字串比較判斷提示不同 (例如 Assert.Equal("Current count: 1", paraElmText);
)。 MarkupMatches
會執行輸入和預期 HTML 標記的語意比較。 語意比較會感知 HTML 語意,這表示忽略微不足道的空白字元等事物。 這可造就更穩定的測試。 如需詳細資訊,請參閱自訂語意 HTML 比較。
其他資源
- 開始使用 bUnit:bUnit 指示包括建立測試專案、參考測試架構套件,以及建置和執行測試的指引。
- 如何建立可維護且可測試的 Blazor 元件 - Egil Hansen - NDC Oslo 2022
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應