events
ASP.NET Core Blazor の Razor コンポーネントをテストする
注意
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、 .NET および .NET Core サポート ポリシーを参照してください。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
作成者: Egil Hansen
Razor コンポーネントのテストは、安定し、保守性に優れた Blazor アプリをリリースする上で重要な作業です。
Razor コンポーネントをテストするために、"テスト対象のコンポーネント" (CUT) に対して次のことが行われます。
- テスト用の関連する入力でレンダリングされます。
- 実行されるテストの種類によっては、操作または変更される可能性があります。 たとえば、ボタンの
onclick
イベントなどのイベント ハンドラーがトリガーされる可能性があります。 - 予想される値について検査されます。 1 つまたは複数の値がテストの予想値と一致すると、テストは合格となります。
Razor のコンポーネントをテストするための一般的な 2 つのアプローチは、エンド ツー エンド (E2E) テストと単体テストです。
単体テスト: 単体テストは、次の機能を提供する単体テスト ライブラリを使用して記述されます。
- コンポーネントのレンダリング。
- コンポーネントの出力と状態の検査。
- イベント ハンドラーとライフ サイクル メソッドのトリガー。
- コンポーネントの動作が正しいことのアサーション。
bUnit は、Razor コンポーネントの単体テストを実現するライブラリの一例です。
E2E テスト: テスト ランナーでは、CUT を含む Blazor アプリを実行し、ブラウザー インスタンスを自動化します。 テスト ツールでは、ブラウザーを介して CUT を検査および操作します。 Playwright for .NET は、Blazor で使用できる E2E テスト フレームワークの一例です。
単体テストでは、Razor コンポーネント (Razor/C#) のみが関係します。 サービスや JS 相互運用などの外部の依存関係は、複製する必要があります。 E2E テストでは、Razor コンポーネントとそのすべての補助インフラストラクチャ (CSS、JSDOM、ブラウザー API など) がテストに含まれます。
"テスト スコープ" では、テストの範囲を説明します。 通常、テスト スコープは、テストの速度に影響します。 単体テストは、アプリのサブシステムのサブセットに対して実行され、通常、ミリ秒単位で実行されます。 E2E テストでは、アプリのサブシステムの広範なグループがテストされ、完了するまで数秒かかることがあります。
単体テストでは、CUT のインスタンスにもアクセスでき、コンポーネントの内部状態の検査と検証を行うことができます。 通常、これは、E2E テストでは行うことができません。
コンポーネントの環境に関しては、E2E テストでは、検証を開始する前に、予想される環境状態に達していることを確認する必要があります。 そうしなければ、結果は予測できません。 単体テストでは、CUT のレンダリングとテストのライフ サイクルはより統合されるため、テストの安定性が向上します。
E2E テストでは、複数のプロセス、ネットワークとディスクの I/O、その他のサブシステムのアクティビティを起動する必要があり、多くの場合、これによってテストの信頼性が低下します。 通常、単体テストは、このような種類の問題とは無関係です。
次の表は、この 2 つのテスト アプローチの違いをまとめたものです。
機能 | 単体テスト | E2E テスト |
---|---|---|
テスト スコープ | Razor component (Razor/C#) のみ | Razor コンポーネント (Razor/C#) と CSS/JS |
テストの実行時間 | ミリ秒 | Seconds |
コンポーネント インスタンスへのアクセス | はい | いいえ |
環境依存 | いいえ | はい |
[信頼性] | 信頼性が高い | 信頼性が低い |
実行するテストの種類を選択する際には、シナリオを考慮します。 次の表では、いくつかのシナリオについて説明します。
シナリオ | 推奨されるアプローチ | 解説 |
---|---|---|
JS 相互運用ロジックのないコンポーネント | 単体テスト | Razor コンポーネント内に JS 相互運用への依存関係がない場合、JS または DOM API にアクセスせずにコンポーネントをテストできます。 このシナリオでは、単体テストを選択することにデメリットはありません。 |
単純な JS 相互運用ロジックがあるコンポーネント | 単体テスト | コンポーネントでは、JS 相互運用を使用して、DOM に対してクエリを実行したり、アニメーションをトリガーしたりするのが一般的です。 IJSRuntime インターフェイスを使用して JS 相互運用を簡単に複製できるので、このシナリオでは、通常、単体テストをお勧めします。 |
複雑な JS コードに依存するコンポーネント | 単体テストと個別の JS テスト | コンポーネントで、JS 相互運用を使用して大きなまたは複雑な JS ライブラリを呼び出すが、Razor コンポーネントと JS ライブラリ間の対話は単純な場合、最適なアプローチは、コンポーネントと JS ライブラリまたはコードを 2 つの個別のパーツと見なして、それぞれを個別にテストすることです。 単体テスト ライブラリを使用して Razor コンポーネントをテストし、JS テスト ライブラリを使用して JS をテストします。 |
ブラウザー DOM の JS 操作に依存するロジックのあるコンポーネント | E2E テスト | コンポーネントの機能が JS および DOM のその操作に依存する場合、1 回の E2E テストで、JS と Blazor コードの両方をまとめて検証します。 これは、Blazor フレームワーク開発者が、Blazor のブラウザー レンダリング ロジックで採用しているアプローチで、C# と JS コードが密結合されます。 ブラウザーで Razor コンポーネントをレンダリングするには、C# と JS コードが連携する必要があります。 |
複製が困難な依存関係を持つサードパーティ製クラス ライブラリに依存するコンポーネント | E2E テスト | コンポーネントの機能が、JS 相互運用など、複製が困難な依存関係を持つサードパーティ製クラス ライブラリに依存している場合、E2E テストは、そのコンポーネントをテストするための唯一のオプションになる可能性があります。 |
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: bUnit の
TestContext
を使用して、Counter
コンポーネントがレンダリングされます。 CUT の段落要素 (<p>
) が検出され、paraElm
に割り当てられます。 Razor 構文では、コンポーネントを bUnit に RenderFragment として渡すことができます。Act: ボタンの要素 (
<button>
) が配置され、Click
を呼び出して選択されます。これにより、カウンターが増分され、段落タグ (<p>
) の内容が更新されます。 段落要素のテキスト コンテンツは、TextContent
を呼び出すことによって取得されます。Assert: テキスト コンテンツで
MarkupMatches
が呼び出され、予想される文字列Current count: 1
と一致するかどうかが検証されます。
注意
MarkupMatches
Assert メソッドは、標準の文字列比較アサーション (たとえば、Assert.Equal("Current count: 1", paraElmText);
) とは異なります。 MarkupMatches
は、入力と予想される HTML マークアップのセマンティック比較を実行します。 セマンティック比較では、HTML セマンティクスが認識されます。つまり、意味のない空白のようなものは無視されます。 これにより、テストの安定性が向上します。 詳細については、「Customizing the Semantic HTML Comparison」 (HTML のセマンティック比較のカスタマイズ) を参照してください。
- Getting Started with bUnit (bUnit の概要): bUnit の説明には、テスト プロジェクトの作成、テスト フレームワーク パッケージの参照、テストの構築と実行に関するガイダンスが含まれています。
- 保守可能でテスト可能な Blazor コンポーネントを作成する方法 - Egil Hansen - NDC Oslo 2022
ASP.NET Core に関するフィードバック
ASP.NET Core はオープンソース プロジェクトです。 フィードバックを提供するにはリンクを選択します。
その他のリソース
トレーニング
モジュール
Visual Studio での C# テスト - Training
Visual Studio のテスト ツールを使用して、C# アプリのテストを開始します。 テストの記述、テスト エクスプローラーの使用、テスト スイートの作成、およびコードを記述するための赤、緑、リファクタリングのパターンの適用について学習します。