bUnitとは?Blazorコンポーネントのテスト方法とインストール・書き方

bUnitは、Blazorコンポーネントをブラウザなしでテストするための.NET向けライブラリです。実ブラウザを起動せずコンポーネントをメモリ上でレンダリングするため、1件あたりミリ秒単位で動作し、通常の単体テストと同じ感覚でCIに組み込めます。この記事では、bUnitの位置づけ、NuGetでのインストール、Blazorコンポーネントの代表的なテストの書き方、そしてv1からv2で変わった点(TestContextの改称)までをまとめます。最新版は2.7.2(2026年3月時点)です。

まとめ

  • bUnitはBlazorコンポーネント専用のテストライブラリ。実ブラウザを使わずレンダリング結果・イベント・状態遷移を検証する。
  • 特定のテストフレームワークに縛られない。xUnit・NUnit・MSTest・TUnitのいずれの上でも動く(「xUnit専用」ではない)。
  • 導入はdotnet add package bunitの1行。テンプレートdotnet new bunitでも新規プロジェクトを作れる。
  • v2ではTestContextBunitContextへ改称。旧TestContextは非推奨([Obsolete])で将来削除されるため、新規コードはBunitContextを使う。
  • ブラウザ実描画やJavaScript連携の検証はbUnitの範囲外。その用途はPlaywright等のE2Eテストと使い分ける。

bUnitとは:Blazorコンポーネントを対象にした単体テストライブラリ

bUnitは、C#で書いたBlazorコンポーネント(.razor)を対象に、レンダリング結果とユーザー操作の挙動を検証するオープンソースのライブラリです。テストフレームワークそのものではなく、xUnit・NUnit・MSTest・TUnitといった既存のフレームワークの「上に載る」形で動きます。そのため、テストの実行・アサーション・レポートは使い慣れたフレームワークの仕組みをそのまま利用できます。

最大の特徴は、SeleniumやPlaywrightのように実ブラウザを立ち上げず、コンポーネントをメモリ上でレンダリングして検証する点です。ブラウザ起動やページ遷移の待ち時間が発生しないため、1テストがミリ秒単位で完了します。クリックや入力といったイベントの発火、パラメータや状態の変化に応じた再レンダリングも再現でき、単体テストの粒度でUIの振る舞いを固定できます。Blazor ServerとWebAssemblyのどちらのホスティングでも、テスト対象はコンポーネント単体なので同じように書けます。

Blazorそのものの位置づけや採用判断はBlazorの将来性と.NET 10時代の採用判断で整理しています。

bUnitのインストール:NuGetパッケージとテンプレート

bUnitはNuGetのbunitパッケージとして配布されています。既存のxUnit(またはNUnit/MSTest)テストプロジェクトに追加する場合は、パッケージを1つ入れるだけです。ゼロから作るならテンプレートが早く、テストフレームワークまで含めた雛形が生成されます。

// 既存のテストプロジェクトに追加する場合
dotnet add package bunit --version 2.7.2

// テンプレートから新規テストプロジェクトを作る場合
dotnet new bunit --framework xunit -o BlazorApp.Tests

テスト対象のBlazorプロジェクトはプロジェクト参照で追加します。bunitパッケージにはbunit.corebunit.webが含まれるため、Web向けのアサーションを個別に入れる必要はありません。Moqのようなモックライブラリは、DIを差し替えるテストで必要になった時点で追加すれば十分です。

Blazorコンポーネントの主要なテストパターン

bUnitのテストは、テストクラスをBunitContextから継承し、RenderComponent<T>()で対象を描画してからアサートする、という流れが基本です。以下、読者が実際に書く頻度の高い4パターンを示します。

レンダリング結果とイベントの検証

FindでDOM要素を取得し、Clickなどで操作した後、MarkupMatchesで期待するHTMLと一致するかを比較します。MarkupMatchesは要素構造・属性・テキストを厳密に突き合わせるため、意図しないUI変更(リグレッション)を検出できます。

using Bunit;
using Xunit;

public class CounterTests : BunitContext   // v2で TestContext から改称
{
    [Fact]
    public void ボタン押下でカウントが増える()
    {
        var cut = RenderComponent<Counter>();
        cut.Find("button").Click();
        cut.Find("p").MarkupMatches("<p>Current count: 1</p>");
    }
}

サービス注入とモック

外部サービスに依存するコンポーネントは、DIコンテナに差し替え用のモックを登録してから描画します。BunitContextServicesプロパティがIServiceCollectionそのものなので、Blazor本体と同じ感覚でサービスを登録できます。これにより、実際のAPIやDBに触れず、返り値を固定した状態で表示ロジックだけを検証できます。

public class WeatherTests : BunitContext
{
    [Fact]
    public void 取得した天気を表示する()
    {
        var mock = new Mock<IWeatherService>();
        mock.Setup(s => s.GetSummary()).Returns("晴れ");
        Services.AddSingleton(mock.Object);

        var cut = RenderComponent<WeatherCard>();

        cut.Find("span").MarkupMatches("<span>晴れ</span>");
    }
}

非同期・遅延ロードの検証

データ取得後に再レンダリングされるコンポーネントは、アサーション時点でまだ更新が終わっていないことがあります。WaitForAssertionを使うと、指定した条件が満たされるまで再レンダリングを待ってから判定するため、タイミング依存のテスト失敗を防げます。ローディング表示から結果表示への切り替えなど、状態が段階的に変わるUIに有効です。

[Fact]
public async Task 非同期ロード後に一覧が表示される()
{
    var cut = RenderComponent<AsyncList>();

    cut.WaitForAssertion(() =>
        cut.Find("li").MarkupMatches("<li>読み込み完了</li>"));
}

パラメータ付き・再利用コンポーネントの検証

共通部品として使うコンポーネントは、パラメータの組み合わせごとに表示や挙動が変わります。RenderComponentの引数でパラメータを与え、入力に応じた出力を検証します。プレースホルダ・初期値・入力反映といった再利用部品の契約を、呼び出し側ごとに固定できます。

var cut = RenderComponent<TextInput>(parameters => parameters
    .Add(p => p.Placeholder, "氏名を入力")
    .Add(p => p.Value, "初期値"));

cut.Find("input").Change("更新後");

Assert.Equal("更新後", cut.Instance.Value);

bUnit v1からv2への主な変更点

ネット上のサンプルの多くはv1系(new TestContext())で書かれており、そのまま2.x環境に貼ると非推奨警告が出ます。移行時に押さえる差分は次のとおりです。

項目 v1系 v2系(2.7.2)
コンテキスト型 TestContext BunitContext(旧名は[Obsolete]で残存)
破棄 IDisposable IDisposableIAsyncDisposable
対象.NET .NET 6/7系中心 .NET 8以上(.NET 10対応)

移行はテストクラスの継承元をTestContextからBunitContextへ置き換えるのが中心です。旧TestContextは互換のため当面残されていますが、将来のバージョンで削除される予定なので、新規に書くコードはBunitContextで統一するのが安全です。「TestContextは非推奨」という警告に遭遇したら、xUnit v3など他フレームワーク側の同名型との衝突回避が改称理由だと理解しておくと混乱しません。

bUnitとブラウザE2Eテスト(Playwright/Selenium)の使い分け

bUnitは万能ではありません。実ブラウザを使わない設計上、JavaScript相互運用(JSInterop)を実際に実行する検証や、CSSの実描画・ブラウザ間の表示差の確認には向きません。bUnitではJSInteropは呼び出しをモックする形で扱うため、「ブラウザで本当にその通り描画・動作するか」までは保証できないからです。

判断の目安はシンプルです。コンポーネント単位のロジック・状態遷移・条件付きレンダリングを高速に固めたいならbUnit。ページをまたぐ操作フロー、認証を含む結合動作、実ブラウザでのJS実行や見た目の検証が目的ならPlaywrightやSeleniumのE2Eを使います。両者は競合ではなく役割分担で、bUnitで大量の分岐を安く押さえ、E2Eは主要動線に絞って少数で回すのが現実的です。ブラウザ側の検証手段としてはPlaywright Component Testの概要と特徴も比較の参考になります。

よくある質問

bUnitとは何ですか?

Blazorコンポーネントをブラウザなしでテストするための.NET向けオープンソースライブラリです。コンポーネントをメモリ上でレンダリングし、表示内容やクリック・入力などの操作結果を単体テストとして検証します。

bUnitの利用に料金はかかりますか?

かかりません。bUnitはオープンソースで無償で利用できます。NuGetのbunitパッケージを追加するだけで導入でき、商用プロジェクトでも使えます。

bUnitを使うにはxUnitが必須ですか?

必須ではありません。bUnitはテストフレームワークに依存せず、xUnit・NUnit・MSTest・TUnitのいずれの上でも動作します。既存プロジェクトで採用しているフレームワークに合わせて選べます。

「TestContext は非推奨」という警告が出るのはなぜですか?

v2でTestContextBunitContextへ改称され、旧名は[Obsolete]として残されているためです。他のテストフレームワークにある同名型との衝突を避けるための変更で、テストクラスの継承元をBunitContextに置き換えれば警告は解消します。

Blazor ServerとWebAssemblyのどちらもテストできますか?

どちらもテストできます。bUnitのテスト対象はコンポーネント単体であり、ホスティングモデルに依存しません。同じテストコードでServer/WebAssembly双方のコンポーネントを検証できます。

関連記事

資料請求

RELATED POSTS 関連記事