Skip to content

Web Components に TDD の適用は難しい

Web Components は再利用性の高い UI コンポーネントを作るうえで非常に有用ですが、その内部構造や振る舞いが特殊であるため、TDD を直接適用しようとするといくつかの困難に直面します。
このドキュメントでは、その理由と、現実的かつ効果的なアプローチについて解説します。

Web Componentsを使う場合、TDDを「UIコンポーネント」そのものに厳密に適用しようとすると難易度が高くなるため、TDDは「アプリケーションのロジック層(ドメイン/ビジネスルール)」に対して適用するのが現実的かつ効果的です。

Web ComponentsとTDDを無理に結びつけず、「UIとロジックの責務分離」をして、ロジック側にTDDを適用するのが現実的で効果的です。 UI層は「接続部分を検証する程度」にとどめ、ロジックの堅牢性をTDDで担保するのがベストプラクティスです。

Web Components × TDD が難しい理由

なぜ Web Components に TDD をそのまま適用するのが難しいのか、具体的な技術的観点から見ていきましょう。

理由詳細
DOM操作と密接で状態が外部依存属性・イベント・スロットなど、外部のHTMLやDOMとの相互作用が多い
状態の変化が非同期属性変更・イベントディスパッチ・描画の完了タイミングなどが async
テストに Shadow DOM 対応が必要shadowRoot の中身まで確認しないと動作保証できない
初期化やライフサイクルが特殊connectedCallback, attributeChangedCallback などを正確にテストするには環境が必要

よって、TDDに向いているのは「ドメインロジック層」

上記のような制約を踏まえると、TDD の効果を最大限に引き出すには、UI ではなくロジック層に注目するのが現実的です。

例:アプリケーション構造の分離

📁 /src
  ├── /components
  │     └── my-user-form.ts       ← Web Component(TDD困難な部分)
  ├── /domain
  │     └── user.ts               ← TDD対象(Userのバリデーション、登録条件など)
  ├── /services
  │     └── user-service.ts       ← TDD対象(登録処理、DB保存など)
  └── /utils
        └── email-validator.ts    ← TDD対象(関数単位)

TDD対象例:

テスト対象例
domain/user.tsUser の生成条件、isValid() のようなドメインロジック
services/user-service.ts登録・重複チェック・通知など、ビジネスルール
utils/email-validator.ts単一関数としてのユニットテスト

UI層(Web Components)は「テスト後」+「最小限の振る舞いテスト」でOK

UI 層もまったくテストしないわけではありませんが、TDD のような厳密なループで行うには適していません。
ここでは、UI に対する適切なテストアプローチについて説明します。

テストスタイル用途
単体ユニットテスト属性・イベントの受け渡しなどシンプルな振る舞い確認
E2Eテスト(Playwrightなど)ユーザー操作を通じた総合動作確認
Storybook + JestUI状態のスナップショットテスト(非推奨だが一部で使われる)

責務を明確に分離する

そのためには、アプリケーション内の各層における責務の分離が不可欠です。
以下のように、ロジック・状態管理・UI を分けて考えると、それぞれに最適なテスト戦略が見えてきます。

対象層テスト戦略
ビジネスロジック層純粋なJavaScriptで実装し、TDDで徹底的にテスト
状態管理層データの流れと状態変化をTDDでテスト
プレゼンテーション層WebComponentsの見た目や振る舞いは、必要に応じて統合テストやビジュアルテストで補完

実際の開発フロー

では、実際にどのような順序で開発・テストを進めるのが効果的なのでしょうか。
TDD を活かした現実的なフローの一例を紹介します。

  1. ロジックやルールを TDD で先に設計・実装
  2. その後 Web Component の UI に「ロジック層を注入」
  3. UI 層では「最低限の振る舞い」だけをテスト(属性変化やイベント発火)

Released under the CC-BY-4.0 license.