日々更新中です!

【脱初心者】Angular×Jasmineで単体テストを書く方法!

  • URLをコピーしました!
悩んでいる男の子

Angularでテストコードを書いてみたいんだけど、情報が少なくてよく分からないんだよね。。
具体的なソースコード付きで教えてもらえると嬉しいな。

こんな悩みを解決します。

  • 本記事の内容
  • Angularの単体テストについて
  • 単体テストの書き方について
  • 具体的なソースコード
  • 本記事の執筆者
プロフィール
いずみん(どこの写真だよ)
  • 元エンジニア(歴7年)、資格保有数約20個(IT系以外も含む)
  • 物販月利50万円⇒脱サラ
  • 物販、システム開発、アフィリエイト、プログラミング、投資をやっています。
  • 物販は彼女と楽しみながらやっています!

今回は、Angular×Jasmineでテストコードを書く方法を解説します。

僕自身、本記事の内容を業務で実践してきたので、Angularの単体テストを書く際に役立つこと間違いなしです。

本記事を読めば、Angular×Jasmineの基礎的な知識が身に付きますよ!

いずみん

サラッと読み終わるので、是非最後まで読んでみてください!

目次

Angularのテストとは

Angularのテストは主に2つあります。

  • 単体テスト(Jasmine+Karma)
  • e2eテスト(protractor or Cypress)

単体テスト(Jasmine+Karma)

AngularにはデフォルトでJasmineKarmaがインストールされています。

テストを実行することで、「spec.ts」ファイルのテストがすべて実行されます

Jasmineはテストフレームワークで、Karmaはテストランナーと覚えておけばOKです。

e2eテスト(protractor or Cypress)

Angularにはデフォルトで「protractor」がインストールされています。

テストを実行することで、e2eフォルダ内のテストがすべて実行されます

e2eテストはシステム全体のテストを行うもの、と覚えておけばOKです。

いずみん

e2eテストについては今回割愛しますね。

単体テスト実行方法

ng test

上記コマンドを実行します。

↑が実行結果になります。

いずみん

全てSUCCESSであればOKです!

特定のファイルだけテストを実行したい場合

fdescribe('SampleComponent', () => {
});

describeの先頭に「f」を付与することで、fを付与したdescribe内のテストのみが実行されます。

非常に便利ですが、fを付与した状態でコミットしないように注意してください。

ソースコード解説

では早速、ソースコードの解説をしていきますね。

いずみん

僕が業務で気になったコードをまとめているので、是非参考にしてみてください。

TestBed

主要なAngularテストユーティリティの1つです。

Angular 日本語ドキュメンテーション

使用例

TestBed.configureTestingModule({
});

CUSTOM_ELEMENTS_SCHEMA

コンポーネントのテストでは、依存関係にあるコンポーネントをテスト内で定義しないと、未知の要素と判断されてエラーになります。

この時に発生するコンソールエラーを回避するために「CUSTOM_ELEMENTS_SCHEMA」を使用します。

使用例

TestBed.configureTestingModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
});

describe

テストのグループです。

describe内でdescribeを定義することも可能です。

使用例

describe('テストのグループ', () => {
});

beforeEach

主に初期化処理を行います。

使用例

beforeEach(() => {
});

detectChanges

change Detectionが行われたことを伝えます。

change Detectionとは、モデルの変更を検知しUIに反映することです。

使用例

beforeEach(() => {
  fixture.detectChanges();
});

expectの種類

expect(component).toBeTruthy();

上記のように、expectを使用してテストを検証します。

Matcherには種類があるので、適切なものを使用します。

項目説明備考
toBe同一かどうか※厳密等価演算子を使って比較
toEqual同一オブジェクトかどうか
toContain期待値が含まれるかどうか
toBeTruthyTrueかどうか
toBeFalsyFalseかどうか
toBeNullNullかどうか
toBeNaNNaNかどうか
toBeLessThan実効値が期待値より大きいかどうか
toBeGreaterThan実効値が期待値より小さいかどうか
toBeDefinedundefinedではない
toBeUndefinedundefinedである
toHaveBeenCalled関数が実行されたかどうか
toHaveBeenCalledWith関数が実行されたかどうか※引数チェックも含む
toThrow例外が発生するかどうか

否定する場合

expect(xxx).not.ToEqual(yyy)

否定する場合は、「not」を付ければOKです。

各テストの書き方

component

主に、取得したデータが正しく表示されているかを確認します。

いずみん

HTMLにベタ書きされている文言等はテストしなくてもOKです。
あまりやる意味もないですし。。

const hogeServiceSpy = jasmine.createSpyObj('HogeService', ['getHoge']);

beforeEach(
  TestBed.configureTestingModule({
    declarations: [SampleComponent],
    providers: [
      { provide: HogeService, useValue: hogeServiceSpy },
    ],
  }).compileComponents();

  hogeServiceSpy.getHoge.and.returnValue(of(getHoge()));
);

取得するデータはspyを使用し、モックから取得するようにします。

spyを使用することで、コンポーネントのテストに集中することができます。

describe('getHoge', () => {
  it('hoge情報取得', () => {
    const mock = getHoge();
    const debugElement = fixture.debugElement;
    expect(debugElement.query(By.css('.id')).nativeElement.textContent).toEqual(mock.id);
  });
});

function getHoge() {
  return {
    id: 1,
  };
}

あとは、HTMLに表示されている内容と実際のモックデータを比較してテストします。

モック化することでサービスに依存しないテストが可能です。

directive

import { HogeDirective } from './hoge.directive';

describe('HogeDirective', () => {
  it('onClick時', () => {
    const directive = new HogeDirective();
    directive.onClick();

    expect(hoge).toHaveBeenCalled();
  });
});

特に特殊なことはなく、ディレクティブのインスタンスを生成し、各処理をテストするだけです。

pipe

import { HogePipe } from './hoge.pipe';

describe('HogePipe', () => {
  const pipe = new HogePipe();

  it('transform', () => {
    expect(pipe.transform('abc')).toBe('abc');
  });
});

pipeはtransformを使うので、上記のようにテストします。

Angular 日本語ドキュメンテーション

その他

@Inputのテスト

子コンポーネントの場合、Inputで値を受け取る場合が多いです。

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-hoge-test',
  templateUrl: './hoge-test.component.html',
  styleUrls: ['./hoge-test.component.scss']
})
export class HogeTestComponent implements OnInit {
  @Input() title: string;
}

上記のようにコンポーネントが定義されているとします。

it('titleのテスト', () => {
  component.title = 'タイトル';
  fixture.detectChanges();

  const element = fixture.debugElement.query(By.css('.title')).nativeElement as HTMLSpanElement;
  expect(element.textContent).toBe('タイトル');
});

↑がテストコードになります。

変数に値を入れた後、detectChangesを忘れないようしてください。

前提条件にクエリパラメータを使う場合

画面によっては、クエリパラメータが付与されていることが前提の場合もあります。

そういった場合は、providersで定義します。

describe('HogeComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      providers: [
        {
          provide: ActivatedRoute,
          useValue: {
            snapshot: {
              paramMap: convertToParamMap({ id: 123 })
            }
          }
        }
      ]
    });
  }));
});

ルーティングのテスト

ルーティングのテストは、ルーティング処理実行後のURLを見て判断します。

redirect() {
  this.router.navigate(['/hoge']);
}

↑のようにserviceのメソッドが定義されているとします。

let router: Router;
let service: HogeService;

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [AppRoutingModule],
    providers: [HogeService],
  });

  router = TestBed.inject(Router);
  service = TestBed.inject(HogeService);
});

it('リダイレクトしていること', fakeAsync(() => {
  service.redirect();
  tick();
  expect(router.url).toBe('/hoge');
}));

↑がテストコードです。

リダイレクト処理なので、念のためasyncを使用しています。

メソッドが実行されたか確認したい場合

メソッドが実行されたかどうかを確認したい場合は、「toHaveBeenCalled」「toHaveBeenCalledWith」を使用します。

a() {
  b();
}

例えば、コンポーネントに↑のようなメソッドがあるとします。

component.a();
expect(component.b).toHaveBeenCalled();

テストコードは↑のようになります。

bはspyOnでモック化しておけばOKです。

まとめ

今回は、Angular×Jasmineでテストコードを書く方法を解説しました。

Angularのテストって情報が少なくて困りますよね。。

ではまた!

  • おすすめ本はこちら!
いずみん

僕は↑の本でAngularの勉強をしました!
非常に分かりやすいのでおすすめです!

  • 自由な生き方がしたいなら!

自由な生き方をするためには、稼ぐスキルを身に付けなければなりません。

当サイト「リバトレ」では稼ぐスキルに関する情報を日々発信しているので、興味のあるものから見て頂ければ嬉しいです。

この記事が気に入ったら
いいね または フォローしてね!

シェアするんやで!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

いずみんのアバター いずみん 自由大好きおじ

自由大好きおじ | 物販月利50万達成⇨脱サラ | 物販(アパレルせどり)・アフィリエイト・プログラミング・投資に関する情報を発信中 | 元エンジニア | 保有資格約20個

コメント

コメントする

目次
閉じる