Angularのユニットテストを開始する方法
序章
プロジェクトがAngularCLI を使用して作成された場合、テストフレームワークとして Jasmine を使用し、テストランナーとして Karma を使用して、すべてのテストの作成を開始できます。 。
Angularは、TestBed
やasync
などのユーティリティも提供しており、非同期コード、コンポーネント、ディレクティブ、またはサービスのテストを容易にします。
この記事では、JasmineとKarmaを使用してAngularで単体テストを作成および実行する方法について学習します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Node.jsはローカルにインストールされます。これは、Node.jsのインストール方法とローカル開発環境の作成に従って実行できます。
- Angularプロジェクトのセットアップにある程度精通している。
このチュートリアルは、ノードv16.2.0、npm
v7.15.1、および@angular/core
v12.0.4で検証されました。
ステップ1—プロジェクトの設定
テストファイルは通常、テストするファイルのすぐ横に配置されますが、必要に応じて、独自の別のディレクトリに配置することもできます。
これらのスペックファイルは、*.spec.ts
の命名規則を使用しています。
まず、@angular/cli
を使用して新しいプロジェクトを作成します。
- ng new angular-unit-test-example
次に、新しく作成されたプロジェクトディレクトリに移動します。
- cd angular-unit-test-example
app.component
の横に、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
を使用し、toBeDefined
、toBeTruthy
、toContain
、toEqual
、[ X121X]、 toBeNull
、…例:expect(myValue).toBeGreaterThan(3);
not
でネガティブアサーションを実行できます:expect(myValue).not.toBeGreaterThan(3);
- カスタムマッチャーを定義することもできます。
TestBed
は、Angular固有のテストに使用できる主要なユーティリティです。 テストスイートのbeforeEach
ブロックでTestBed.configureTestingModule
を使用し、declarations
、NgModule
と同様の値のオブジェクトを指定します。 X142X]、およびimports
。 次に、compileComponents
への呼び出しをチェーンして、宣言されたコンポーネントをコンパイルするようにAngularに指示できます。
TestBed.createComponent
でcomponent 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
ロジックに置き換えます。
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
を開き、コンテンツを次のコードに置き換えます。
<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
に再度アクセスし、次のコード行に置き換えます。
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');
});
});
すべてのテストでこれらが必要なため、fixture
とdebugElement
をbeforeEach
ブロックに直接割り当てます。 また、@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テストガイドについては、公式ドキュメントを参照することもできます。