Testing - Vueアプリの品質を守る3層戦略
ロードマップ: Vue.js学習ロードマップ
What(何についてか)
Testing は、Vueアプリケーションを安全に変更し続けるための品質保証戦略である。自動テストはリグレッションを防ぐだけでなく、関数、モジュール、composable、component をテスト可能な形へ分解する圧力としても機能する。
Vue公式は、テスト戦略を次の3層で整理している。
- Unit Testing
- Component Testing
- End-to-End Testing
これは優劣ではなく、守る対象が異なる別種の検査である。
Why(なぜ必要か)
アプリケーションは、ロジック、UI、画面遷移、ネットワーク連携など多様な壊れ方をする。テストを導入することで、変更時の退行を早期に検知し、チームが安心して機能追加やリファクタリングを進められる。
また、Testing は単なる後付けの検査ではない。テストしづらいコードは責務分離が悪い可能性が高く、Testing は設計改善のフィードバック装置にもなる。
Vue公式は、テストはできるだけ早く書き始めることを推奨している。後から導入するほど依存が増え、テストを追加しにくくなるためである。
How(どう動くか)
Testing strategy の3層
flowchart TD A["Unit Testing"] --> AU["小さなロジックの正しさ"] B["Component Testing"] --> BU["UI部品の振る舞い"] C["E2E Testing"] --> CU["アプリ全体の利用フロー"]
Unit Testing
Unit test は、関数、class、module、composable のような小さく独立した単位を検証する。目的は business logic の正しさを速く、局所的に検証することにある。
export function increment(current, max = 10) {
if (current < max) {
return current + 1
}
return current
}import { increment } from './helpers'
describe('increment', () => {
test('increments the current number by 1', () => {
expect(increment(0, 10)).toBe(1)
})
test('does not increment the current number over the max', () => {
expect(increment(10, 10)).toBe(10)
})
test('has a default max of 10', () => {
expect(increment(10)).toBe(10)
})
})Vue特有の unit test 対象としては composable が重要である。lifecycle や mount を伴うものは特別な扱いが必要な場合もあるが、再利用ロジックを切り出しておくほど unit test しやすくなる。
Component Testing
Component test は、Vueアプリの主要構成要素である component の振る舞いを検証する。粒度としては unit test より一段広く、integration test 的な性格を持つ。
主に検証対象となるのは次の public interface である。
- props
- emitted events
- slots
- DOM output
- user interaction に対する反応
設計姿勢として重要なのは、component を blackbox に扱うことである。内部 state や private method を直接検査するのではなく、入力に対してユーザーから見える出力がどう変わるかを検証する。
flowchart LR I["props / slots / user interaction"] --> C["Component"] --> O["DOM / emitted events"]
例えば Stepper component であれば、内部実装ではなく、max prop を渡した状態で increment ボタンをクリックした結果、表示値が正しく更新されるかを見る。
テストの観点
- Visual logic: props や slots に応じた描画結果を検証する
- Behavioral logic: user action に対する DOM 更新や emitted event を検証する
避けるべきこと
- private state の直接検査
- private method の直接テスト
- 実装詳細に依存した brittle なテスト
- snapshot test のみに依存すること
End-to-End Testing
E2E test は、ユーザーが実際に利用するフローをアプリ全体で検証する。複数ページにまたがる画面遷移や、本番に近いブラウザ挙動、ネットワーク連携を含めた統合確認が対象になる。
unit test や component test では局所的な正しさは守れるが、router、state、UI、API が組み合わさった時の破綻は E2E でないと検知しにくい。
一方で、E2E は実行コストが高く、遅く、環境依存も増える。そのため、全機能を E2E で守るのではなく、ログイン、主要CRUD、重要な画面遷移など、クリティカルなユーザーフローへ絞るのが基本になる。
Vueにおけるツール選定
Unit Testing
- Vitest を推奨
- 理由: Vite の transform pipeline と設定をそのまま使え、導入が軽く高速だから
- Jest は既存資産がある場合の移行先候補であり、新規Viteプロジェクトでは第一候補ではない
Component Testing
- Vitest + @vue/test-utils
- headless な component や、Nodeベースで十分なDOMテスト向き
- Cypress Component Testing
- style、ネイティブDOMイベント、ブラウザ実挙動の確認が重要な場合に向く
End-to-End Testing
- Playwright を推奨
- Chromium / WebKit / Firefox 対応
- 高い debuggability
- traces、parallelization、headless / headed 実行を備える
- Cypress も強力な選択肢
- GUIやデバッグ体験が良い
- Component Testing との接続も強い
Options API → Composition API 差分(補足)
| 項目 | Options API(旧) | Composition API(新) |
|---|---|---|
| テスト対象のロジック切り出し | methods / computed / mixins に分散しやすい | composable や module に切り出しやすい |
| UIロジックの再利用単位 | mixins 中心 | composable 中心 |
| テストしやすさ | this 依存が混ざりやすい | pure function / composable に寄せやすい |
| 推奨unit基盤 | Jest文化が多かった | Vitest + Vite が自然 |
Key Concepts
| 用語 | 説明 |
|---|---|
| Unit Testing | 小さく独立したロジック単位を検証するテスト |
| Component Testing | component の公開インターフェースと振る舞いを検証するテスト |
| E2E Testing | アプリ全体のユーザーフローを検証するテスト |
| blackbox testing | 実装詳細ではなく入力と出力の振る舞いを見る観点 |
| public interface | props、events、slots、DOM など外から観測可能な契約 |
| regression | 変更により既存挙動が壊れること |
| brittle test | 実装変更だけで壊れやすい不安定なテスト |
| Vitest | Vite ベースプロジェクト向けの高速テストフレームワーク |
| Vue Test Utils | Vue component のマウントと操作を支援するテストユーティリティ |
| Playwright | モダンな E2E テスト基盤 |
| Cypress | E2E と component testing を支援するブラウザベースのテスト基盤 |
実務での判断軸
- business logic はできるだけ component から切り離し、unit test しやすい構造へ寄せる
- Vueでは component test が中核であり、blackbox 発想で public interface を検証する
- E2E は高コストなので、重要フローに絞って配置する
- Testing は品質保証だけでなく、責務分離と設計健全性を保つための仕組みでもある