-
Notifications
You must be signed in to change notification settings - Fork 17
Step5:テストを作成する
redux-plutoでは Service と Reducer のテスト作成を推薦しています。
今回はこれらのテストを作成していきましょう。
redux-pluto ではテストに jest を利用しています
Service のテストでは、API 呼び出しが想定通りに行われているのかをテストします。
テストファイルは src/server/services/__test__ 配下に作成していきます。
src/server/services/__test__/Hello.read.test.ts
+import * as assert from "power-assert";
+import configs from "../../configs";
+import Hello from "../Hello";
+
+const getComments = require("../../../../spec/agreed/hello/getComments");
+
+test("Hello: read success", async () => {
+ const hello = new Hello(configs);
+ const result = await (hello.read as any)({}, {}, {});
+ assert.deepEqual(result, getComments.response.body.results);
+});
src/server/services/__test__/Hello.create.test.ts
+import * as assert from "power-assert";
+import configs from "../../configs";
+import Hello from "../Hello";
+
+test("Hello: create success", async () => {
+ const hello = new Hello(configs);
+ const body = { text: "hello" };
+ const result = await hello.create({}, {}, {}, body, {});
+ assert.ok(result.id);
+ assert.equal(result.text, body.text);
+});
利用module
power-asert
assert.ok: 引数に与えた値が true かどうかをテストする関数
assert.equal: 第1引数と第2引数の値が同値かテストする関数
assert.deepEqual: オブジェクトの最下位層まで一致しているかをテストする関数
以下のコマンドを実行すると jest.config.js 内の testMatch にマッチする全てのテストが実行されます。
$ npm test
以下のようにテストが success すれば成功です!
Test Suites: 1 skipped, 24 passed, 24 of 25 total
Tests: 1 skipped, 38 passed, 39 total
Snapshots: 1 passed, 1 total
Time: 34.196s
Ran all test suites.
Reducer のテストでは、dispatch された Action によって想定通りに state が更新されているのかをテストします。
Redux 配下には __test__ フォルダが 「src/shared/redux/__test__」、「src/shared/redux/modules/__test__」 の2種類あります。
前者には middleware などの利用が必要な redux 全体が絡むテスト、後者には module 内の reducer だけで完結するテストを書いていきます。
テストの中で module 内の INITIAL_STATE を利用したいので、まず初めに INITIAL_STATE を export しましょう。
src/shared/redux/modules/hello.js
-const INITIAL_STATE = {
+export const INITIAL_STATE = {
次に src/shared/redux/__test__ 配下にテストを作成していきましょう。
src/shared/redux/__tests__/hello.getComments.test.js
+import * as Fetchr from "fetchr"; // Fetcher の インポート
+import * as assert from "power-assert";
+import { FetchrStatic } from "./types";
+import { getComments, INITIAL_STATE } from "../modules/hello";
+import { createStore } from "./lib/storeUtils"; // store 作成のための util
+
+let needFailure: any = null; // リクエストを失敗させるかどうかのフラグ
+
+const comments = [{ id: "0001", text: "hello" }]; // API からの レスポンスデータ
+
+(Fetchr as FetchrStatic).registerService({
+ // reducer の中では Fetcher を利用して api 呼び出しを行っているため、Fetcher の登録を行う
+ name: "hello",
+ read(req, resource, params, config, cb) {
+ return needFailure
+ ? cb(new Error("failure")) // リクエスト失敗フラグが true の時には error を返す
+ : cb(needFailure, { comments }); // リクエスト失敗フラグが false の時には comments を返す
+ },
+});
+
+test("hello: getComments success", async () => {
+ // リクエスト成功時のテスト
+ const store = createStore({ cookie: {} });
+ assert.deepEqual(store.getState().app.hello, INITIAL_STATE); // 初期状態であることを確認
+
+ await store.dispatch(getComments());
+
+ // getComments を dispatch
+ assert.deepEqual(store.getState().app.hello, {
+ // state が 想定どうりに更新されているか確認
+ comments,
+ isVisible: true,
+ loaded: true,
+ loading: false,
+ });
+});
+
+test("hello: getComments failure", async done => {
+ needFailure = true; // リクエスト失敗フラグを立てる
+ const store = createStore({ cookie: {} });
+ assert.deepEqual(store.getState().app.hello, INITIAL_STATE);
+ try {
+ await store.dispatch(getComments());
+ } catch (_e) {
+ assert.deepEqual(store.getState().app.hello, {
+ comments: [],
+ isVisible: true,
+ error: true,
+ loading: false,
+ loaded: false,
+ });
+ done();
+ }
+});
src/shared/redux/__tests__/hello.postComment.test.js
+import * as Fetchr from "fetchr";
+import * as assert from "power-assert";
+import { FetchrStatic } from "./types";
+import { postComment, INITIAL_STATE } from "../modules/hello"; // postComment と INITIAL_STATE をインポート
+import { createStore } from "./lib/storeUtils";
+
+let needFailure: any = null;
+
+(Fetchr as FetchrStatic).registerService({
+ name: "hello",
+ create(req, resource, params, body, config, cb) {
+ return needFailure
+ ? cb(new Error("failure"))
+ : // リクエスト成功時には送られてきたテキストに id を採番したオブジェクトを返す
+ cb(needFailure, { id: "0001", text: body.text });
+ },
+});
+
+test("hello: postComment success", async () => {
+ const store = createStore({ cookie: {} });
+
+ assert.deepEqual(store.getState().app.hello, INITIAL_STATE);
+ const body = { text: "hello" };
+ await store.dispatch(postComment(body));
+ assert.deepEqual(store.getState().app.hello, {
+ comments: [{ id: "0001", text: body.text }],
+ isVisible: true,
+ loaded: true,
+ loading: false,
+ });
+});
+
+test("hello: postComments failure", async done => {
+ needFailure = true;
+ const store = createStore({ cookie: {} });
+ assert.deepEqual(store.getState().app.hello, INITIAL_STATE);
+ const body = { text: "hello" };
+ try {
+ await store.dispatch(postComment(body));
+ } catch (_e) {
+ assert.deepEqual(store.getState().app.hello, {
+ comments: [],
+ isVisible: true,
+ error: true,
+ loading: false,
+ loaded: false,
+ });
+ done();
+ }
+});
次に、src/shared/redux/modules/__test__ 配下に module に閉じたテストを作成していきます。
src/shared/redux/modules/tests/hello.test.ts
+import * as assert from "power-assert";
+import Immutable from "seamless-immutable";
+import reducer, { changeVisibility } from "../hello"; // reducer と テストしたい関数(changeVisibility) をインポート
+
+test("State: changeVisibility", done => {
+ const changeVisibilityAction = changeVisibility();
+ const INITIAL_STATE = Immutable({
+ // INITIAL_STATE を イミュータブルなオブジェクトとして設定
+ isVisible: false,
+ comments: [],
+ loading: true,
+ loaded: false,
+ });
+ let state = reducer(INITIAL_STATE as any, changeVisibilityAction as any);
+ // 設定した初期値に対して changeVisibilityAction を発火
+ assert.deepEqual(state, {
+ isVisible: true,
+ comments: [],
+ loading: true,
+ loaded: false,
+ });
+
+ // isVisible が true の状態でもう一度 changeVisibilityAction を発火
+ state = reducer(state, changeVisibilityAction as any);
+ assert.deepEqual(state, {
+ isVisible: false,
+ comments: [],
+ loading: true,
+ loaded: false,
+ });
+ done();
+});
コンソールで以下のコマンドを実行し、再度テストを走らせてみましょう。
$ npm test
以下のようにテストが success すれば成功です!
Test Suites: 1 skipped, 27 passed, 27 of 28 total
Tests: 1 skipped, 43 passed, 44 total
Snapshots: 1 passed, 1 total
Time: 38.994s
Ran all test suites.