Theme
SD MILIEU

2022-6-2

モックする際はモックが正しい引数で呼び出されているかも検証しようという話

言いたいことはタイトル通り。

例えば、以下のような商品名を取得する [GET] /product_names APIがあるとする。

// リクエストパラメータ
{
  // 対象のIDの配列
  "ids[]": string[]
}

// レスポンス
{
  // 商品IDをキーとする商品名のレコード
  product_names: Record<string, string>
}

そして、このAPIをラップする fetchProductNames(ids: string[]): Promise<Record<string, string>> というような関数を作成したとする。

で、以下のようなMSWを使用したテストコードを書いた。(importは省略)

const server = setupServer()

beforeAll(() => {
  server.listen()
})

afterAll(() => {
  server.close()
})

describe('fetchProductNames', () => {
  test('正常系', async () => {
    const targetProductIds = ['10', '11']

    server.use(
      rest.get('/product_names', (req, res, ctx) => {
        return res(
          ctx.status(200),
          ctx.json({
            product_names: {
              10: 'hoge',
              11: 'fuga',
            },
          })
        )
      })
    )

    const result = await fetchProductNames(targetProductIds)
    const expected: Record<string, string> = {
      '10': 'hoge',
      '11': 'fuga'
    }
    expect(result).toEqual(expected)
  })
})

このテストには不足している検証内容がある。それは「APIへのリクエスト内容が正しいか否か」である。

例えば、APIへのリクエストパラメータとして ids[] が本来必要なところ、 ids と実装してしまっていた場合でもテストが成功してしまう。

なので、以下のように書き換えるべき。

const server = setupServer()

beforeAll(() => {
  server.listen()
})

afterAll(() => {
  server.close()
})

describe('fetchProductNames', () => {
  test('正常系', async () => {
    const targetProductIds = ['10', '11']

    server.use(
      rest.get('/product_names', (req, res, ctx) => {
        // ここから追加
        const ids = req.url.searchParams.getAll('ids[]')
        targetProductIds.forEach((id, index) => {
          // 送られたリクエストパラメータが想定と異なる際にエラーでテストを落とす
          if (id !== ids[index]) throw new Error()
        })
        // ここまで追加

        return res(
          ctx.status(200),
          ctx.json({
            product_names: {
              10: 'hoge',
              11: 'fuga',
            },
          })
        )
      })
    )

    const result = await fetchProductNames(targetProductIds)
    const expected: Record<string, string> = {
      '10': 'hoge',
      '11': 'fuga'
    }
    expect(result).toEqual(expected)
  })
})

今回はAPIのモックだったけど、関数などのモックをする際も同様に正しい引数で呼ばれているかを検証する必要がある。