Contents
Angularコンポーネントテストの概要と目的
Angularアプリケーションの品質を担保するためには、コンポーネントテストが不可欠です。現時点(2023年)では、Karmaが主流ですが、将来的にVitestが採用される可能性がある技術動向としては注目されています。TestBedはAngular公式に推奨されるテストユーティリティで、コンポーネントの挙動を正確に検証するための基盤を提供します。本記事では、TestBedベースの最新手法を解説し、読者が即座に導入可能な知識を得られるようにします。
TestBed.createComponent()の使い方とテストフロー
コンポーネントテストは、TestBed.createComponent()を使って実装を開始します。このメソッドにより、テスト環境で対象のコンポーネントがインスタンス化され、ライフサイクルイベントやDOM操作を検証できます。
コンポーネントインスタンス作成の基本
createComponent()は以下の手順で使用します。
TestBed.configureTestingModule()でモックサービスや依存関係を設定TestBed.createComponent(YourComponent)でコンポーネントを作成fixture.detectChanges()で変更検知をトリガー
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
beforeEach(() => { TestBed.configureTestingModule({ declarations: [YourComponent], providers: [{ provide: UserService, useClass: MockUserService }] }); }); it('コンポーネントが初期化される', () => { const fixture = TestBed.createComponent(YourComponent); const component = fixture.componentInstance; fixture.detectChanges(); expect(component).toBeTruthy(); }); |
ライフサイクルイベントの検証手順
ライフサイクルイベント(ngOnInit, ngOnDestroyなど)は、テストで再現・検証可能です。
| イベント | 検証方法 |
|---|---|
| ngOnInit | コンポーネントインスタンスの初期化メソッドをSpyで監視 |
| ngOnDestroy | fixture.destroy()を呼び出し、破棄ロジックを検証 |
|
1 2 3 4 |
spyOn(component, 'ngOnInit'); fixture.detectChanges(); expect(component.ngOnInit).toHaveBeenCalled(); |
NO_ERRORS_SCHEMAとDebugElementの活用法
テスト対象外のエラー回避やDOM操作にはNO_ERRORS_SCHEMAとDebugElementが有効です。
不要なエラーチェックの回避方法
Angularは、未定義の要素や属性を検出するとエラーを発生させますが、テストではこの挙動を無視する必要があります。
|
1 2 3 4 5 |
TestBed.configureTestingModule({ declarations: [YourComponent], schemas: [NO_ERRORS_SCHEMA] }); |
DOM要素操作の実践例
DebugElementはDOM要素にアクセスし、イベント発火やテキスト検証を簡単にします。
|
1 2 3 4 5 6 |
const debugEl = fixture.debugElement; const button = debugEl.query(By.css('button')).nativeElement; button.click(); // イベント発火 expect(debugEl.nativeElement.textContent).toContain('Success'); |
依存性注入の差し替えによるテストの柔軟性向上
コンポーネントが外部サービスに依存する場合、テストではモックを使用して実装を切り替えます。
サービス置き換えパターン
providersオプションでモックサービスを注入できます。
|
1 2 3 4 5 6 |
TestBed.configureTestingModule({ providers: [ { provide: YourService, useClass: MockYourService } ] }); |
Spyの活用シーン
Spyを使ってメソッド呼び出しを監視・制御します。
|
1 2 3 4 |
const spy = spyOn(mockService, 'fetchData'); fixture.detectChanges(); expect(spy).toHaveBeenCalledWith('testParam'); |
HTTPモック作成のベストプラクティス
HttpClientによる非同期通信は、HttpTestingControllerでモック化できます。
HttpClientのモック戦略
HttpTestingControllerを注入- モックレスポンスを作成
- リクエストを監視し、期待値と照合
|
1 2 3 |
const mockResponse = { data: 'test' }; httpMock.expectOne('/api/test').flush(mockResponse); |
非同期テストの待ち処理
非同期操作はasync/awaitまたはdone()で待ちます。
| 方法 | 説明 |
|---|---|
| async/await | より簡潔で読みやすいコード |
| done() | 検証が完了するまでテストを停止 |
|
1 2 3 4 5 |
it('非同期リクエスト成功', async () => { const response = await service.getData(); expect(response).toEqual({ data: 'test' }); }); |
Vitest導入時の設定手順
Vitestへの移行は以下のステップで完了します。
jest.config.jsからvitest.config.tsへの移行
jest.config.jsを削除、vitest.config.tsを作成- Angular CLIとTypeScriptの設定を調整(例:
tsconfig.jsonにVitestのモジュールを追加)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// vitest.config.ts import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { globals: true, environment: 'jsdom', coverage: { reporter: ['text', 'json'] } } }); |
テストスクリプトの更新
package.json内のテストコマンドを変更し、Angular CLIと連携する設定ファイル(例: angular-cli.json)を調整します。
|
1 2 3 4 |
"scripts": { "test": "vitest" } |
注意: VitestはAngular CLIとの完全な互換性が確認されていないため、一部のカスタムスクリプトや設定ファイルの調整が必要です。
HttpTestingControllerとVitestの併用ガイド
HttpTestingControllerをVitestで使用する際には以下の手順を参考にし、実装リスクを低減してください。
HttpClientTestingModuleをimportしてモック環境を準備TestBed.configureTestingModule()でHttpTestingControllerを注入設定- Vitestの非同期処理と連携するテストコードを記述
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
describe('AuthComponent', () => { let component: AuthComponent; let fixture: ComponentFixture<AuthComponent>; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ declarations: [AuthComponent], imports: [HttpClientTestingModule], providers: [ { provide: AuthService, useClass: MockAuthService } ] }); fixture = TestBed.createComponent(AuthComponent); component = fixture.componentInstance; httpMock = TestBed.inject(HttpTestingController); }); it('認証成功時にメッセージが表示される', async () => { const mockResponse = { success: true }; httpMock.expectOne('/api/auth').flush(mockResponse); await fixture.whenStable(); expect(fixture.nativeElement.textContent).toContain('ログイン成功'); }); }); |
実際のテストコードを書いてみよう
以下は、ユーザー認証機能をテストするコード例です。
コンポーネントとサービスの定義(仮)
|
1 2 3 4 5 |
// auth.component.ts export class AuthComponent { constructor(private authService: AuthService) {} } |
サマリ
- TestBed.createComponent()でコンポーネントテストを開始し、ライフサイクルイベントを検証
- NO_ERRORS_SCHEMAとDebugElementを使い、DOM操作やエラー回避を実現
- DI差し替えで外部サービスの挙動を制御し、依存性を柔軟に管理
- HttpTestingControllerを使って非同期通信をモック化し、テスト環境構築を簡素化
- Vitestへの移行は設定ファイルとスクリプト更新で完了可能
以上が、Angularコンポーネントテストの実践的な手順です。実際にテストコードを書いてみることで、理解が深まります。