Jestを使ってJavaScriptで快適にテストする
Jestとは
JavaScriptのテストフレームワークです。
フロントエンド向けのテストフレームワークで注目されました。
ただJest自体はフロントエンドに限定されずに有用なテストフレームワークです。
Jestのメリット
- テストを書き始めるまでが簡単
- Matcherが揃っている
- Mockが簡単に用意できる
これらのメリットについて具体的な実装を交えて説明します。
テストの書き方
テストを書く準備
Jestをインストールする
npm install --save-dev jest
テストファイルを書く
const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
これで始められます。
toBe
などのテストの検証に必要なMatcherが最初から用意されています。
テストの記述の仕方はJasmineやMochaといったテストフレームワークと同様です。
Matcherを使う
toBe
,toEqual
のMatcherを覚えておけば大抵のことはカバーできると思われます。
FizzBuzzの結果を返すcreateFizzBuzzList
メソッドで動作確認をします。
FizzBuzz.js
module.exports = class FizzBuzz { static createFizzBuzzList(num) { const list = []; for (let i = 1; i <= num; i++) { if (i % 15 === 0) { list.push("FizzBuzz"); } else if (i % 3 === 0) { list.push("Fizz"); } else if (i % 5 === 0) { list.push("Buzz"); } else { list.push(i.toString()); } } return list; } };
toBe
で等価であることを検証できます。
FizzBuzz.spec.js
test("FizzBuzz test", () => { const actual = FizzBuzz.createFizzBuzzList(16); expect(actual.length).toBe(16); expect(actual[0]).toBe("1"); expect(actual[1]).toBe("2"); expect(actual[2]).toBe("Fizz"); expect(actual[3]).toBe("4"); expect(actual[4]).toBe("Buzz"); expect(actual[5]).toBe("Fizz"); expect(actual[6]).toBe("7"); expect(actual[7]).toBe("8"); expect(actual[8]).toBe("Fizz"); expect(actual[9]).toBe("Buzz"); expect(actual[10]).toBe("11"); expect(actual[11]).toBe("Fizz"); expect(actual[12]).toBe("13"); expect(actual[13]).toBe("14"); expect(actual[14]).toBe("FizzBuzz"); expect(actual[15]).toBe("16"); });
toEqual
でオブジェクトや配列の値を検証できます。
FizzBuzz.spec.js
test("FizzBuzz test custom", () => { const expected = [ "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz", "16" ]; const actual = FizzBuzz.createFizzBuzzList(16); expect(actual.length).toBe(16); expect(actual).toEqual(expected); });
Snapshotテストを使う
実行結果を保存するのに有用なSnapshotテストという機能があります。
Matcherのテストとは違い、期待値となる値を定義する必要がなくなるのでテストコードがシンプルになります。
FizzBuzz.spec.js
test("FizzBuzz snapshot test", () => { const actual = FizzBuzz.createFizzBuzzList(16); expect(actual).toMatchSnapshot(); });
通常のMatcherとの使い分けとしては、Snapshotテストはプロダクションコードの結果が正しいことが前提です。
正しいと判断するためのテストを書いて、そのテストを通すためのプロダクションコードを書くといったTDDのようなアプローチは取れなくなります。
実行結果を保持することで壊れていないかを確認するのがテストの目的となることもあるため、Snapshotテストは有用な手段だと思います。
Mockを使う
Jestでは自動モック機能というものがあり、簡単にMock作成が可能です。
AccountDao.js
module.exports = class AccountDao { findOrNull(userId) { return userId; } };
Authentication.js
module.exports = class Authentication { getDao() { return this.dao; } setDao(val) { this.dao = val; } authenticate(userId, password) { const account = this.dao.findOrNull(userId); if (account === null) return null; return account.password === password ? account : null; } };
Authentication.spec.js
const Authentication = require("../src/Authentication"); const AccountDao = require("../src/AccountDao"); jest.mock("../src/AccountDao"); describe("Authentication", () => { test("not exist account", () => { const sut = new Authentication(); const dao = new AccountDao(); dao.findOrNull.mockReturnValue(null); sut.setDao(dao); expect(sut.authenticate("user001", "pw123")).toBeNull(); }); });
jest.mock
関数でモジュールを全てMock化したオブジェクトを作成することができます。
これにより、new AccountDao()
で作成したオブジェクトは全てMockになります。
dao
オブジェクトのfindOrNull
メソッドはMockになり、mockReturnValue
関数などのMock用の関数を実行することが可能になります。
まとめ
テストを書くときにMockを使うのが前提となることが多いと思います。個人的には自動でMock化してくれる機能が強力です。
Jestで快適なテストライフを!
参考資料
Jestで書いたテストコード集です
github.com