3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オフグリッドAdvent Calendar 2024

Day 10

Jasmine × Karmaで始めるAngular単体テスト入門

Posted at

はじめに

Angular開発において、単体テストはアプリケーションの品質を確保する重要なプロセスです。AngularではデフォルトでJasmineとKarmaが設定されており、これらを使うことで簡単にテスト環境を構築できます。この記事では、JasmineとKarmaの基本を理解し、コンポーネントやサービスの単体テストを実装する方法を解説します。


目次

  1. JasmineとKarmaとは?
  2. Angularのテスト環境のセットアップ
  3. 基本的なJasmineの構文
  4. コンポーネントの単体テスト
  5. サービスの単体テスト
  6. 実践:簡単なテストケースの作成
  7. トラブルシューティングとベストプラクティス

1. JasmineとKarmaとは?

  • Jasmine
    • JavaScriptのテストフレームワーク。BDD(振る舞い駆動開発)スタイルで記述できる。
    • シンプルな構文で、テストケースの記述が容易。
  • Karma
    • テストランナー。ブラウザでテストを実行し、結果をリアルタイムで確認できる。
    • Angular CLIに組み込まれており、セットアップ不要で利用可能。

2. Angularのテスト環境のセットアップ

Angular CLIで生成されたプロジェクトには、すでにJasmineとKarmaが設定されています。

テストの実行方法

ng test

これにより、Karmaが起動し、テストがブラウザ上で実行されます。

テストファイル

  • ファイル名: *.spec.ts
  • 各コンポーネントやサービスのテストファイルが自動生成されます。

3. 基本的なJasmineの構文

テストケースの基本構造

describe('テストスイート名', () => {
  it('テストケース名', () => {
    expect(true).toBe(true);
  });
});

マッチャの例

  • toBe:厳密な等価性を確認
  • toEqual:オブジェクトの値を比較
  • toContain:配列や文字列に特定の要素が含まれるかを確認
expect(1 + 1).toBe(2);
expect({ name: 'Angular' }).toEqual({ name: 'Angular' });
expect([1, 2, 3]).toContain(2);

4. コンポーネントの単体テスト

コンポーネントのテストでは、テンプレートのレンダリングやユーザーイベントの処理を確認します。

テスト対象コンポーネント

@Component({
  selector: 'app-my-component',
  template: `<button (click)="increment()">Click me</button><p>{{ count }}</p>`
})
export class MyComponent {
  count = 0;

  increment() {
    this.count++;
  }
}

テストケース

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyComponent } from './my-component.component';

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [MyComponent]
    }).compileComponents();

    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should increment count on button click', () => {
    const button = fixture.nativeElement.querySelector('button');
    button.click();
    fixture.detectChanges();
    expect(component.count).toBe(1);
  });
});

5. サービスの単体テスト

サービスはビジネスロジックやデータ取得を扱う重要な部分です。

テスト対象サービス

@Injectable({
  providedIn: 'root',
})
export class MyService {
  getMessage(): string {
    return 'Hello, Service!';
  }
}

テストケース

import { TestBed } from '@angular/core/testing';
import { MyService } from './my-service.service';

describe('MyService', () => {
  let service: MyService;

  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(MyService);
  });

  it('should return correct message', () => {
    expect(service.getMessage()).toBe('Hello, Service!');
  });
});

6. 実践:簡単なテストケースの作成

以下の例では、ToDoアプリのテストを実装します。

テスト対象

@Component({
  selector: 'app-todo',
  template: `<input [(ngModel)]="newTask"><button (click)="addTask()">Add</button><ul><li *ngFor="let task of tasks">{{ task }}</li></ul>`
})
export class TodoComponent {
  tasks: string[] = [];
  newTask = '';

  addTask() {
    if (this.newTask.trim()) {
      this.tasks.push(this.newTask);
      this.newTask = '';
    }
  }
}

テストケース

it('should add a task to the list', () => {
  component.newTask = 'Test Task';
  component.addTask();
  expect(component.tasks).toContain('Test Task');
});

7. トラブルシューティングとベストプラクティス

  • テストが失敗する場合の対処法
    • TestBedの設定を見直す。
    • 非同期処理の場合、asyncfakeAsyncを活用する。
  • ベストプラクティス
    • テストを小さく、独立したものにする。
    • 可能な限りモックを使用して依存関係をテスト対象から分離する。

おわりに

JasmineとKarmaを使えば、Angularアプリケーションの単体テストを効率的に実施できます。この記事で紹介した方法を参考に、ぜひプロジェクトにテストを導入してみてください。


3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?