Angularのユニットテストを開始する方法

提供:Dev Guides
移動先:案内検索

序章

プロジェクトがAngularCLI を使用して作成された場合、テストフレームワークとして Jasmine を使用し、テストランナーとして Karma を使用して、すべてのテストを開始する準備が整います。 。

Angularは、TestBedasyncなどのユーティリティも提供しており、非同期コード、コンポーネント、ディレクティブ、またはサービスのテストを容易にします。

この記事では、JasmineとKarmaを使用したAngularでの単体テストの作成と実行について学習します。

前提条件

このチュートリアルを完了するには、次のものが必要です。

このチュートリアルは、ノードv16.2.0、npm v7.15.1、および@angular/corev12.0.4で検証されました。

ステップ1—プロジェクトの設定

テストファイルは通常、テストするファイルのすぐ横に配置されますが、必要に応じて、独自の別のディレクトリに配置することもできます。

これらのスペックファイルは、*.spec.tsの命名規則を使用しています。

まず、@angular/cliを使用して新しいプロジェクトを作成します。

ng new angular-unit-test-example

次に、新しく作成されたプロジェクトディレクトリに移動します。

cd angular-unit-test-example

app.componentの横に、app.component.spec.tsファイルがあります。 このファイルを開き、その内容を調べます。

src / app / app.component.spec.ts

import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });

  it(`should have as title 'angular-unit-test-example'`, () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app.title).toEqual('angular-unit-test-example');
  });

  it('should render title', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('.content span').textContent).toContain('angular-unit-test-example app is running!');
  });
});

ジャスミンを理解する

まず、ジャスミンについて知っておくべき重要なことがいくつかあります。

  • describeブロックはテストスイートを定義し、各itブロックは個別のテスト用です。
  • beforeEachは各テストの前に実行され、テストのsetup部分に使用されます。
  • afterEachは各テストの後に実行され、テストのteardown部分に使用されます。
  • beforeAllおよびafterAllを使用することもでき、これらはすべてのテストの前または後に1回実行されます。
  • expectを使用し、toBeDefinedtoBeTruthytoContaintoEqual、 [ X121X]、toBeNull、…例:expect(myValue).toBeGreaterThan(3);
  • notでネガティブアサーションを実行できます:expect(myValue).not.toBeGreaterThan(3);
  • カスタムマッチャーを定義することもできます。

TestBedは、Angular固有のテストに使用できる主要なユーティリティです。 テストスイートのbeforeEachブロックでTestBed.configureTestingModuleを使用し、declarations、[の通常のNgModuleと同様の値のオブジェクトを指定します。 X142X]、およびimports。 次に、compileComponentsへの呼び出しをチェーンして、宣言されたコンポーネントをコンパイルするようにAngularに指示できます。

TestBed.createComponentcomponent fixtureを作成できます。 フィクスチャはdebugElementにアクセスでき、コンポーネントフィクスチャの内部にアクセスできます。

変更検出は自動的に行われないため、フィクスチャでdetectChangesを呼び出して、Angularに変更検出を実行するように指示します。

テストのコールバック関数またはbeforeEachの最初の引数をasyncでラップすると、Angularは非同期コンパイルを実行し、asyncブロック内のコンテンツの準備が整うまで待機できます。継続します。

テストを理解する

この最初のテストはshould create the appという名前で、expectを使用して、toBeTruthy()でコンポーネントの存在を確認します。

2番目のテストはshould have as title 'angular-unit-test-example'という名前で、expectを使用して、app.titleの値がtoEqual()の文字列'angular-unit-test-example'と等しいことを確認します。

3番目のテストはshould render titleという名前で、expectを使用して、コンパイルされたコードのテキスト'angular-unit-test-example app is running!'toContain()をチェックします。

ターミナルで、次のコマンドを実行します。

ng test

3つのテストすべてが実行され、テスト結果が表示されます。

Output3 specs, 0 failures, randomized with seed 84683
AppComponent
* should have as title 'angular-unit-test-example'
* should create the app
* should render title

現在、3つのテストすべてに合格しています。

ステップ2—サンプルコンポーネントの構築

値をインクリメントまたはデクリメントするコンポーネントを作成しましょう。

コードエディタでapp.component.tsを開き、次のコード行をincrementおよびdecrementロジックに置き換えます。

src / app / app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  value = 0;
  message!: string;

  increment() {
    if (this.value < 15) {
      this.value += 1;
      this.message = '';
    } else {
      this.message = 'Maximum reached!';
    }
  }

  decrement() {
    if (this.value > 0) {
      this.value -= 1;
      this.message = '';
    } else {
      this.message = 'Minimum reached!';
    }
  }
}

コードエディタでapp.component.htmlを開き、コンテンツを次のコードに置き換えます。

src / app / app.component.html

<h1>{{ value }}</h1>

<hr>

<button (click)="increment()" class="increment">Increment</button>

<button (click)="decrement()" class="decrement">Decrement</button>

<p class="message">
  {{ message }}
</p>

この時点で、app.component.tsおよびapp.component.htmlのバージョンが改訂されているはずです。

ステップ3—テストスイートの構築

コードエディタでapp.component.spec.tsに再度アクセスし、次のコード行に置き換えます。

src / app / app.component.spec.ts

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

import { AppComponent } from './app.component';

describe('AppComponent', () => {
  let fixture: ComponentFixture<AppComponent>;
  let debugElement: DebugElement;

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

    fixture = TestBed.createComponent(AppComponent);
    debugElement = fixture.debugElement;
  }));

  it('should increment and decrement value', () => {
    fixture.componentInstance.increment();
    expect(fixture.componentInstance.value).toEqual(1);

    fixture.componentInstance.decrement();
    expect(fixture.componentInstance.value).toEqual(0);
  });

  it('should increment value in template', () => {
    debugElement
      .query(By.css('button.increment'))
      .triggerEventHandler('click', null);

    fixture.detectChanges();

    const value = debugElement.query(By.css('h1')).nativeElement.innerText;

    expect(value).toEqual('1');
  });

  it('should stop at 0 and show minimum message', () => {
    debugElement
      .query(By.css('button.decrement'))
      .triggerEventHandler('click', null);

    fixture.detectChanges();

    const message = debugElement.query(By.css('p.message')).nativeElement.innerText;

    expect(fixture.componentInstance.value).toEqual(0);
    expect(message).toContain('Minimum');
  });

  it('should stop at 15 and show maximum message', () => {
    fixture.componentInstance.value = 15;
    debugElement
      .query(By.css('button.increment'))
      .triggerEventHandler('click', null);
      
    fixture.detectChanges();

    const message = debugElement.query(By.css('p.message')).nativeElement.innerText;

    expect(fixture.componentInstance.value).toEqual(15);
    expect(message).toContain('Maximum');
  });
});

すべてのテストでこれらが必要なため、fixturedebugElementbeforeEachブロックに直接割り当てます。 また、@angular/core/testingからComponentFixtureをインポートし、@angular/coreからDebugElementをインポートして、強く入力します。

最初のテストでは、コンポーネントインスタンス自体のメソッドを呼び出します。

残りのテストでは、DebugElementを使用してボタンのクリックをトリガーします。 DebugElementに述語をとるqueryメソッドがあることに注意してください。 ここでは、Byユーティリティとそのcssメソッドを使用して、テンプレート内の特定の要素を検索します。 DebugElementには、DOMに直接アクセスするためのnativeElementメソッドもあります。

また、最後の3つのテストでfixture.detectChangesを使用して、Jasmineのexpectでアサーションを実行する前に、変更検出を実行するようにAngularに指示しました。

変更を加えたら、ターミナルからng testコマンドを実行します。

ng test

これにより、Karmaが監視モードで起動するため、ファイルが変更されるたびにテストが再コンパイルされます。

Output4 specs, 0 failures, randomized with seed 27239
AppComponent
* should increment value in template
* should increment and decrement value
* should stop at 0 and show minimum message
* should stop at 15 and show maximum message

4つのテストすべてに合格します。

結論

この記事では、JasmineとKarmaを使用したAngularでの単体テストの作成と実行について学習します。 これで、主要なAngularテストユーティリティについて理解し、単純なコンポーネントのテストを書き始めることができます。

依存関係のあるコンポーネントのテスト、サービスのテスト、およびモック、スタブ、およびスパイの使用で学習を続けます。

詳細なAngularテストガイドについては、公式ドキュメントを参照することもできます。