はじめに
前回の記事では、JasmineとKarmaを用いた基本的な単体テストの方法を学びました。本記事では、より実践的な内容として、モックを使った依存関係の分離方法と、テストカバレッジの取得・向上方法を解説します。モックを活用することで、外部依存を排除し、テストを効率的に行えるようになります。
目次
- モックとは?
- モックを活用した単体テストの実践例
- 非同期処理のテストとモック
- カバレッジの取得方法
- カバレッジを向上させるヒント
- おすすめのツールとリソース
1. モックとは?
モック(Mock)は、テスト対象が依存するオブジェクトやサービスの代わりに使用する偽の実装です。これにより、依存関係に影響されず、テスト対象の動作を独立して検証できます。
-
なぜモックを使うのか?
- 外部依存(APIコール、データベースアクセス)を排除できる。
- 特定の状況を簡単にシミュレートできる。
- テストが速く、再現性が高くなる。
2. モックを活用した単体テストの実践例
対象サービス
MyService
がAPIからデータを取得する簡単なサービスを想定します。
@Injectable({
providedIn: 'root',
})
export class MyService {
fetchData(): Observable<string[]> {
return of(['Item 1', 'Item 2', 'Item 3']);
}
}
モックを利用したテストケース
以下のコードは、MyService
の依存関係をモックし、コンポーネントのテストを行う例です。
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyComponent } from './my-component.component';
import { MyService } from './my-service.service';
import { of } from 'rxjs';
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let mockService: jasmine.SpyObj<MyService>;
beforeEach(() => {
// モックサービスの作成
mockService = jasmine.createSpyObj('MyService', ['fetchData']);
mockService.fetchData.and.returnValue(of(['Mock Item 1', 'Mock Item 2']));
TestBed.configureTestingModule({
declarations: [MyComponent],
providers: [
{ provide: MyService, useValue: mockService }, // モックを提供
],
}).compileComponents();
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should fetch mock data on initialization', () => {
expect(component.items).toEqual(['Mock Item 1', 'Mock Item 2']);
expect(mockService.fetchData).toHaveBeenCalled();
});
});
ポイント解説
-
jasmine.createSpyObj
: メソッドを持つモックオブジェクトを生成。 -
and.returnValue
: モックメソッドの戻り値を指定。 -
providers
: Angularの依存性注入を使い、モックをテスト対象に注入。
3. 非同期処理のテストとモック
対象サービス
API呼び出しを含む非同期処理の例です。
fetchData(): Observable<string[]> {
return new Observable((observer) => {
setTimeout(() => {
observer.next(['Async Item 1', 'Async Item 2']);
observer.complete();
}, 1000);
});
}
非同期処理のテストケース
非同期処理はfakeAsync
またはasync
を使用してテストします。
it('should handle async data correctly', fakeAsync(() => {
mockService.fetchData.and.returnValue(
of(['Async Mock Item 1', 'Async Mock Item 2'])
);
component.ngOnInit();
tick(1000); // 仮想時間を進める
expect(component.items).toEqual(['Async Mock Item 1', 'Async Mock Item 2']);
}));
4. カバレッジの取得方法
カバレッジレポートの生成
以下のコマンドを実行します:
ng test --code-coverage
**カバレッジレポートの保存場所
テスト実行後、coverageディレクトリにレポートが出力されます。
coverage/
└── my-angular-app/
├── index.html
├── ...
カバレッジレポートの確認
-
レポートの内容:
- Statements: 実行されたコード行の割合。
- Branches: 条件分岐の網羅率。
- Functions: 呼び出された関数の割合。
ブラウザでindex.html
を開き、視覚的に確認できます。
5. カバレッジを向上させるヒント
未カバー部分の特定
カバレッジレポートで「赤く表示」される部分が、未カバーのコードです。これに基づいてテストケースを追加しましょう。
よくある見落としポイント
- 条件分岐(
if
,switch
)の網羅 - 例外処理やエラーハンドリングの確認
- 初期化ロジック(
ngOnInit
など)のテスト
おわりに
モックを活用することで、外部依存を切り離し、より効率的かつ信頼性の高い単体テストを実現できます。また、カバレッジレポートを通じてテストの網羅性を評価し、さらなる品質向上に取り組むことが可能です。今回学んだ内容をもとに、あなたのプロジェクトでもテスト環境を強化してみましょう!