カテゴリー
【Angular】KarmaでDirectiveのユニットテストをおこなう
※ 当ページには【広告/PR】を含む場合があります。
2019/07/09
2022/08/10
Angularの単体テストとしては、現在のところ余り使われなくなってしまった
Angularプロジェクトを作成する
以下、ファイル構造を示します。 (※ node_modules フォルダ以下の深い闇を避けるためにtreeでは除外します)
$ tree -I node_modules -L 5
.
├── README.md
├── angular.json
├── browserslist
├── e2e
│ ├── protractor.conf.js
│ ├── src
│ │ ├── app.e2e-spec.ts
│ │ └── app.po.ts
│ └── tsconfig.json
├── karma.conf.js
├── package.json
├── src
│ ├── app
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── components
│ │ │ └── my-str-tmpl1
│ │ │ ├── my-str-tmpl1.component.scss
│ │ │ ├── my-str-tmpl1.component.spec.ts
│ │ │ └── my-str-tmpl1.component.ts
│ │ └── directives
│ │ └── my-tmpl-def1
│ │ ├── my-tmpl-def1.directive.spec.ts
│ │ └── my-tmpl-def1.directive.ts
│ ├── assets
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.scss
│ └── test.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
├── tslint.json
└── yarn.lock
今回は、
src/app/directives/my-tmpl-def1/
テスト用のDirectiveを作成する
今回はHTMLのp要素の文字を赤くするだけのDirectiveを作成します。
完成品のビューは以下のようになります。

Directiveの使い方は割愛しますが、
my-str-tmpl1
import {
Component
} from '@angular/core';
@Component({
selector: 'app-my-str-tmpl1',
template: `
<div appMyTmplDef1>Hello {{name}}</div>
`,
styleUrls: ['./my-str-tmpl1.component.scss']
})
export class MyStrTmpl1Component {
private name: string;
constructor() {
this.name = 'ANGULAR 2+';
}
}
my-tmpl-def1.directive.ts
以下が今回のDirectiveの実装です。
...要素の文字を赤くしているだけです。
import {
Directive,
ElementRef,
Renderer2,
OnInit
} from '@angular/core';
@Directive({
selector: '[appMyTmplDef1]'
})
export class MyTmplDef1Directive implements OnInit {
constructor(
private el: ElementRef,
private renderer: Renderer2
) {}
ngOnInit() {
this.renderer.setStyle(this.el.nativeElement, 'color', 'red');
}
}
ちなみに、angular cli で Direvtiveを新規作成する場合のショートハンドコマンドには
ng g d [Direvtive名]
my-tmpl-def1.directive.spec.ts
ではテストコードを作成しましょう。
まずは完成形を以下に示します。
import { Component } from '@angular/core';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { MyTmplDef1Directive } from './my-tmpl-def1.directive';
// Simple mocking component
@Component({
template: '<p appMyTmplDef1>Cool Unit Test for Directives</p>'
})
class MockingComponent {
constructor() { }
}
describe('MyTmplDef1Directive', () => {
let component: MockingComponent;
let fixture: ComponentFixture<MockingComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
MockingComponent,
MyTmplDef1Directive
]
});
fixture = TestBed.createComponent(MockingComponent);
component = fixture.componentInstance;
});
it('should create a component', () => {
expect(component).toBeDefined();
});
it('should capitalize style against p element', () => {
const elem: HTMLElement = fixture.debugElement.nativeElement;
const p: HTMLElement = elem.querySelector('p');
// Apply style at the directive to the testing component
fixture.detectChanges(); // !important
// 'color' property should be set red
expect(p.style.color).toBe('red');
});
});
それでは、このコードについて以下に解説をいれましょう。
Mocking Component
通常、Directiveは単体では機能せずComponentに付随して働きます。
単体テストではDirectiveの実行できるような模擬のコンポーネントを準備する必要があります。
上記のコード内では、
...
// Simple mocking component
@Component({
template: '<p appMyTmplDef1>Cool Unit Test for Directives</p>'
})
class MockingComponent {
constructor() { }
}
...
としている箇所に該当いています。
ComponentFixture
Directiveの単体テストに欠かせないのが、ビルドインのユーティリティである
ComponentFixture
名前の通り、Componentに装着させて補助使うようです。
以下、テスト内(describeメソッドの中身)だけ見て行きますと、
let component: MockingComponent;
let fixture: ComponentFixture<MockingComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
MockingComponent,
MyTmplDef1Directive
]
});
fixture = TestBed.createComponent(MockingComponent);
component = fixture.componentInstance;
});
...
の部分で、テストに入る前の下ごしらえを
beforeEach
順序として、まずはComponentFixtureを定義し、そこから被験コンポーネントの実体を変数
component
で、肝心のDirectiveが正常に機能しているか(今回は文字を赤くしているか)のテストが、以下の部分です。
...
const elem: HTMLElement = fixture.debugElement.nativeElement;
const p: HTMLElement = elem.querySelector('p');
// Apply style of the directive to test component
fixture.detectChanges(); // !important
// 'color' should be set red
expect(p.style.color).toBe('red');
...
ComponentFixureのインスタンスから、まず
debugElement.nativeElement
そのテンプレートからp要素を
querySelector
このp要素を引き出した時点では、
appMyTmplDef1
よってDirectiveをローカルで手動実行する為に、今回もっとも重要な手続きは、
fixture.detectChanges();
を適用させなければならないということです。
これはDirectiveにイベントリスナーを組み込んでテストする際には、イベント関数を発火させる度にその都度
detectChanges
以上、最近のAngularに置いて Directive を使う機会は少ないかもしれませんが、ぜひDirectiveの単体テストをお手元でお試しください。
参考
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー