在 ASP.NET Core Razor 中測試 Blazor 元件
注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
作者:Egil Hansen
測試 Razor 元件是發行穩定且可維護 Blazor 應用程式的重要層面。
若要測試 Razor 元件,受測元件 (CUT) 為:
- 使用測試的相關輸入轉譯。
- 視所執行的測試類型而定,可能受限於互動或修改。 例如,可以觸發事件處理常式,例如按鈕的
onclick
事件。 - 檢驗預期的值是否存在。 當一或多個受檢的值符合測試的預期值時,測試就會通過。
測試方法
測試 Razor 元件的兩種常見方法為端對端 (E2E) 測試和單元測試:
單元測試:單元測試是以提供下列各項的單元測試程式庫撰寫:
- 元件渲染。
- 檢查元件輸出和狀態。
- 觸發事件處理常式和生命週期方法。
- 元件行為正確的斷言。
bUnit 是可啟用 Razor 元件單元測試的程式庫範例。
E2E 測試:測試執行器會執行包含 CUT 的 Blazor 應用程式,並將瀏覽器執行個體自動化。 測試工具會透過瀏覽器檢查並與 CUT 互動。 適用於 .NET 的 Playwright 是 E2E 測試架構的範例,可與 Blazor 應用程式搭配使用。
在單元測試中,只涉及 Razor 元件 (Razor/C#)。 必須模擬外部相依性,例如服務和互操作性JS。 在 E2E 測試中,Razor 元件及其所有輔助基礎結構都是測試的一部分,包括 CSS、JS、DOM 和瀏覽器 API。
「測試範圍」描述測試的範圍有多廣泛。 測試範圍通常會影響測試的速度。 單元測試會在應用程式的子系統子集上執行,且通常會以毫秒為單位執行。 E2E 測試會測試應用程式子系統的廣泛群組,可能需要幾秒鐘的時間才能完成。
單元測試也提供 CUT 執行個體的存取權,允許檢查和驗證元件的內部狀態。 這在 E2E 測試中通常不可能。
就元件的環境而言,E2E 測試必須確定在驗證開始之前,已達到預期的環境狀態。 否則,無法預測結果。 在單元測試中,CUT 轉譯和測試生命週期更加整合,可改善測試穩定性。
E2E 測試牽涉到啟動多個處理序、網路和磁碟 I/O,以及通常會導致測試可靠性不佳的其他子系統活動。 單元測試通常可避免這幾種問題。
下表摘要說明這兩種測試方法之間的差異。
能力 | 單元測試 | 端到端測試 |
---|---|---|
測試範圍 | 僅適用於 Razor 元件 (Razor/C#) | CSS/JS 的 Razor 元件 (Razor/C#) |
測試執行時間 | 毫秒 | 秒 |
存取元件執行個體 | 是 | 不 |
對環境敏感 | 不 | 是 |
可靠性 | 更加可靠 | 較不可靠 |
選擇最適當的測試方法
選擇要執行的測試類型時,請考量情境。 下表描述一些考量。
情境 | 建議的方法 | 備註 |
---|---|---|
不含 JS interop 邏輯的元件 | 單元測試 | 當 JS 元件中沒有 Razor Interop 的相依性時,不需存取 JS 或 DOM API 即可測試該元件。 在此情節中,選擇單元測試沒有任何缺點。 |
具有簡單 JS Interop 邏輯的元件 | 單元測試 | 元件通常會透過 JS Interop 查詢 DOM 或觸發動畫。 在此情境中,通常慣用單元測試,因為透過 JS 介面模擬 IJSRuntime 互動相當簡單。 |
相依於複雜 JS 程式碼的元件 | 單元測試和個別 JS 測試 | 如果元件使用 JS Interop 呼叫大型或複雜的 JS 程式庫,但 Razor 元件與 JS 程式庫之間的互動很簡單,則最佳方法可能是將元件和 JS 程式庫或程式碼視為兩個不同的部分並各自分開測試。 使用單元測試程式庫測試 Razor 元件,並使用 JS 測試程式庫測試 JS。 |
邏輯依賴於瀏覽器 DOM 操作的元件 | E2E 測試 | 當元件的功能相依於 JS 及其 DOM 操作時,請在 E2E 測試中一起確認 JS 和 Blazor 程式碼。 這是 Blazor 架構開發人員在 Blazor 的瀏覽器渲染邏輯中採用的方法,其包含緊密結合的 C# 和 JS 程式碼。 C# 和 JS 程式碼必須一起運作,才能在瀏覽器中正確轉譯 Razor 元件。 |
相依於具有難以模擬相依性的第三方類別庫的元件 | 端到端測試 | 當元件的功能相依於具有難以模擬相依性的第三方類別庫 (例如 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 測試從 A 到 Z - 埃吉爾漢森 - NDC 倫敦 2025 (NDC 倫敦)