20
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

この記事は Angular Advent Calendar 2018 の 18日目の記事です。
今回は最近NgRxの新機能として追加されたMockStoreについて書きたいと思います。

NgRxの基本的な使い方については14日目でkiita312さんが書かれていますので、ぜひそちらをご参考ください。
Ngrxをこれから始める人への入門ガイド

MockStoreとは

MockStoreとは、Storeを使ったComponentでのテストを簡単に行えるようにする為のモジュールです。
10月末にmasterにマージされ、v7.0.0でリリース予定となりました。

まだドキュメントが作成されておらずngrx.ioにも記載がないのですが、機能自体はstableとなっています。
非常に便利なので、v7(beta)を使用している方はこの記事を参考にぜひ使い始めてみてください。

残念ながらv7は現在(2018-12-18時点)まだstableとしてリリースされていないため、6系を使用している方はもう少しだけ待つ必要があります。

MockStoreの目的

MockStoreはStoreを使用しているComponentのテストをシンプルに書けるようにするために作られています。

NgRxではComponentはStoreに対してselect/dispatchを行うだけの関係で、StoreやReducerの実装を知る必要がありません。これらは完全な疎結合な関係になっています。しかし、実際にテストを書く際は通常のモジュール設定を行うのと同様にStoreとReducerを設定する必要があります。つまりComponentのテストを書く為には必要なStoreとReducerの関係を理解して一つ一つ設定する必要があります。これは本来不要な作業で面倒なだけです。

MockStoreを使用すればこれらの設定をすることなくStoreを使用することができます。

例として、MockStoreを使用しない場合とした場合のComponentのテスト設定を比較してみましょう。

MockStoreを使わないComponentのテスト設定
TestBed.configureTestingModule({
  imports: [
    StoreModule.forRoot({
      users: combineReducers(userReducers),
    }),
  ],
})

Componentのテスト準備としてStoreModuleの設定と関連するReducerの設定が必要になります。

MockStoreを使ったComponentのテスト設定
TestBed.configureTestingModule({
  providers: provideMockStore(),
});

これだけです。StoreやReducerの設定がなくなり非常にシンプルになります。

MockStoreの使い方

では実際にMockStoreの使用方法を見ていきましょう。
基本的にStateを設定するだけのモジュールなので、初期値設定と値変更の2種類の機能しかありません。

Importの設定

MockStoreは @ngrx/store/testing のモジュールから提供されています。v7を使用している場合は追加でインストールすることなくすぐに利用できます。

import { MockStore, provideMockStore } from '@ngrx/store/testing';

Stateの初期値の設定

MockStoreは先程の provideMockStore に初期値となるStateを渡すことが出来ます。指定しない場合は undefined が初期値として使われます。

interface MockStoreConfig<T> {
  initialState?: T;
}

function provideMockStore<T = any>(config: MockStoreConfig<T> = {}): Provider[];

実際に以下のように使用することができます。

describe('Stateの初期値の設定', () => {
  let mockStore: MockStore<any>;
  const initialState = {
    users: [{ id: 1, name: 'user1' }, { id: 2, name: 'user2' }],
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: provideMockStore({ initialState }),
    });

    mockStore = TestBed.get(Store);
  });

  it('Storeの初期値はinitialStateで設定されている', (done: any) => {
    mockStore.subscribe(val => {
      expect(val).toEqual(initialState);
      done();
    });
  });
});

この記事ではComponentのテストのサンプルコードは割愛しますが、OnInit内で store.select() をしている場合はこの初期設定を使用すると良いでしょう。

Stateの値の変更

MockStoreではReducerを使用しないので、Stateの値の更新方法が変わります。Stateの値を変更したい時はActionをdispatchするのではなく MockStore.setState というメソッドを使用して、任意のタイミングで手動でStateを設定します。

export class MockStore<T> extends Store<T> {
  setState(nextState: T): void;
}

実際に以下のように使用することができます。

describe('Stateの値の変更', () => {
  let mockStore: MockStore<any>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: provideMockStore(),
    });

    mockStore = TestBed.get(Store);
  });

  it('Stateの値はsetStateを使用していつでも変更することが出来る', (done: any) => {
    const newState = {
      users: [{ id: 3, name: 'user3' }, { id: 4, name: 'user4' }],
    };

    mockStore.setState(newState);

    mockStore.subscribe(val => {
      expect(val).toEqual(newState);
      done();
    });
  });
});

なかなか直感的に使用することが出来ます。
Stateの状態ごとにComponentをテストする際などだいぶ見通し良く書くことが出来るようになるかと思います。

おわりに

以上がMockStoreの機能になります。
この記事では概要までの紹介として、実際にComponentのテストの書き方などは別の記事で書ければと思います。

余談ですが provideMockStore のような機能がEffectsにも存在していて、 provideMockActions という関数を使うことでEffectsのテストを簡単に書けたりします。
NgRxは非常にテストが書きやすい設計になっていて個人的にとても良いライブラリだと思います。MockStore、ぜひこれから使用していってください。

明日19日目の記事はaoshiさんです!

20
10
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
20
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?