Jest で テストをテスト仕様書っぽく書いてみよう


jest-simple-template

いきなりですが、Jestの機能の一つ、describe.each を利用して、テストドキュメントっぽく テストを書く ライブラリを作りました。

このパッケージを使うと、テストがこんな感じで書けます。

import handler from '../src/target'
import mocks from './mocks'

/* data input */
let request = {}

/**
 * Test Case Definition
 *
 * [0]: test description
 * [1]: request(input)
 * [2]: expect(output)
 */
const testCase = [
    [
        // [0]: description
        {
            name: 'OK',
            description: 'should return succeeded response'
        },
        // [1]: request
        request,
        // [2]: expected
        (result: {}) => {
            expect(result).toBe(1)
        }
    ],
    [
        // [0]: description
        {
            name: 'Duplicated',
            description: 'should return duplicate something error'
        },
        // [1]: request
        request,
        // [2]: expected
        (result: {}) => {
            expect(result).toBe('error')
        }
    ]
    /* ここに、テストブロックをどんどん足していく */

]

describe.each(testCase)('Test Category1', (d, r, e) => {
    beforeEach(() => {
        jest.resetAllMocks()
    })
    const testMeta = d as TestCaseMetaData
    it(`${testMeta.name}:${testMeta.description}`, async () => {
        if (mocks.hasOwnProperty(testMeta.name)) {
            mocks[testMeta.name]()
        }

        // @ts-ignore
        const result = await handler(r)
        const expected = e as (result: any) => void
        expected(result)
    })
})

このテンプレートパッケージで、私的にはそこそこ快適にテストが書けていると感じたので、共有することにします。

コンセプト

コンセプトとしては、Jest の describe.each は、引数に input、outputもまぜまぜにした Array を取り、ぐるぐる回す方式なので、配列の各 Index にこちらで意味を与えてやれば、テスト仕様書っぽく書けるのでは? という発想が発端です。

describe.each に渡す配列のindexに以下のような意味を持たせます。

  • index[0] - テストの説明
  • index[1] - テストへの入力
  • index[2] - 出力の検証

この発想は Rails の CoC(Convention Over Configuration) が元になっていて、ある程度名前付けなどを規約として決めてしまったほうがコードが読みやすく、短くなるのではないか? というところから来ています。

mocking

上の方法だけだと、Mockを書くのにテストが大きくなってしまい、せっかくのドキュメントが見づらいことになってしまったので、mockは別のファイルにしました。 ここでも CoC の考えかたを取り入れて、 先ほどの説明で、index[0] で定義したnameと一致するものを探して取ってくるようにしました。


const mocks: Mocks = {
    OK: () => {
      // write the code of mocking some objects
    },
    Duplicated: () => {
      // write the code of mocking some objects
    }
}

export default mocks

結果、テストファイルは、describe.each が一つだけ。
テストの内容は、jest.describe の Arrayで表現した形が整いました。

みなさんのテストコードを書くのが少し楽になってくれたらよいなと思います。