Dev Study
← 解説「ng testとテストランナー — 保存のたびに回る開発リズム」に戻る

サンプルコードで身につける: ng testとテストランナー — 保存のたびに回る開発リズム

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1ng test の watch モードと開発リズム

ng test は起動したまま待機し、保存のたびに関連テストを再実行します。エディタの隣にターミナルを置き、緑と赤の切り替わりを見ながら書くのがテスト駆動の基本リズムです。

# watch モードで起動(既定)。終了するまで待機し続ける
ng test

# 開発のリズム:
#   1. テストか実装を編集して保存
#   2. 数秒で関連テストが自動再実行される
#   3. ✓(緑)なら次へ、✗(赤)なら出力を読んで直す
#
# ターミナルはエディタの隣に開いたままにしておくと、
# 保存のたびに「答え合わせ」が返ってくる

2describe / it / beforeEach の構造

describe が章、it が1つの検証、beforeEach が毎回の準備という役割分担です。この構造は Vitest でも Karma(Jasmine)でも共通なので、一度覚えればランナーが変わっても書き方は同じです。

// describe: テストのグループ(対象ごとに1つ作る)
describe('Counter', () => {
  let fixture: ComponentFixture<Counter>;

  // beforeEach: 各 it の前に毎回実行される準備
  beforeEach(() => {
    TestBed.configureTestingModule({ imports: [Counter] });
    fixture = TestBed.createComponent(Counter);
    fixture.detectChanges();
  });

  // it: 1つの検証。「1つの it に1つの関心事」が原則
  it('初期値は0', () => {
    expect(fixture.nativeElement.textContent).toContain('0');
  });

  it('ボタンで増える', () => {
    fixture.nativeElement.querySelector('button')?.click();
    fixture.detectChanges();
    expect(fixture.nativeElement.textContent).toContain('1');
  });
});

3beforeEach で組み立てを共通化する

TestBed の組み立てを各 it にコピーすると、テストが増えたときの修正が大変です。共通の準備は beforeEach に寄せ、it には検証だけを書くのが読みやすいテストの定番の形です。

// Before: 各 it で毎回組み立てている(重複だらけ)
// it('A', () => {
//   TestBed.configureTestingModule({ imports: [Header] });
//   const fixture = TestBed.createComponent(Header); // …毎回同じ
// });

// After: 準備は beforeEach に1回だけ書く
describe('Header', () => {
  let fixture: ComponentFixture<Header>;
  let el: HTMLElement;

  beforeEach(() => {
    TestBed.configureTestingModule({ imports: [Header] });
    fixture = TestBed.createComponent(Header);
    fixture.detectChanges();
    el = fixture.nativeElement;
  });

  it('タイトルが出る', () => {
    expect(el.textContent).toContain('マイアプリ');
  });
  // it が増えても準備のコードは増えない
});

4CIで使う実行オプション

watch モードは開発用で、CIでは1回実行して終了する形にします。カバレッジを出せば「どこがテストされていないか」も数字で見えます。チーム開発ではCIでの自動実行が品質の門番になります。

# 1回だけ実行して終了する(CI向けの基本形)
ng test --watch=false

# カバレッジ(テストが通ったコードの割合)を計測する
ng test --watch=false --code-coverage
# => coverage/ フォルダにレポートが出力される

# CIの使い方の典型:
#   ・プルリクエストのたびに ng test --watch=false を自動実行
#   ・1本でも失敗したらマージをブロックする
# → 「テストが通らないコードは本流に入らない」仕組みを作る

5VitestとKarma — 記事を読むときの見分け方

v21以降の新規プロジェクトの標準ランナーは Vitest で、それ以前は Karma でした。ネットの記事がどちらの前提かで設定の説明が変わりますが、テストコード自体の書き方はほぼ共通です。

# ランナーの変遷:
#   〜v20 : Karma が標準(ブラウザを起動してテストを流す)
#   v21〜 : Vitest が新しい標準(高速・設定がシンプル)

# 記事を読むときの見分け方:
#   ・karma.conf.js の話が出てくる      → Karma 前提(古め)
#   ・vitest の設定や出力の話が出てくる → Vitest 前提(新しめ)

# 安心してよい点:
#   describe / it / beforeEach / expect の書き方はどちらも同じ。
#   TestBed などAngular側のテストAPIもランナーに依存しない。
#   ランナーが替わっても、書いたテスト資産はほぼそのまま活きる