[TypeScript] Property based testing やってみる
概要
Property-based testing という概念を最近やっと知ったので、Rustで試してみたのが → こちら 。TypeScriptでも試してみる。
TypeScript には fast-check いうライブラリがあるようなのでこれを導入して試してみる
導入方法
yarn add -D fast-check
テスト書いてみる
テスト対象
ちょうどブログ記事にシリーズごとにまとめられる機能を作った → こんな感じ
それ用のメタデータ追加を取得するコードを書いたのでテスト対象として使う
series.ts
import { createHash } from 'crypto'
import { unique } from '../lib/arrays'
import { getAllPosts } from './posts'
type Series = {
hash: string
title: string
}
export const getSeries = (allPosts: { series?: string }[]): Series[] =>
unique(
allPosts
.flatMap(post => post.series)
.filter((series): series is string => series !== undefined)
).map(title => {
const md5 = createHash('md5')
const hash = md5.update(title, 'binary').digest('hex')
return { hash, title }
})
export const getAllSeries = (): Series[] => {
const allPosts = getAllPosts(['series'])
return getSeries(allPosts)
}
テストコード
series.test.ts
import { createHash } from 'crypto'
import fc from 'fast-check'
import { describe, expect, test } from 'vitest'
import { getSeries } from './series'
describe('getSeries', () => {
test('md5 と title の組みが全て正しい', async () => {
const post = fc.record({
series: fc.option(fc.string(), { nil: undefined })
})
fc.assert(
fc.property(fc.array(post), posts => {
const actual = getSeries(posts)
actual.forEach(({ hash, title }) => {
const md5 = createHash('md5')
const expected = md5.update(title, 'binary').digest('hex')
expect(hash).toEqual(expected)
})
})
)
})
})
所感
- zodみたいな感じでテストデータの型を作れば、テストデータはFaker.js で作ったみたいなデータが挿入される
- Faker.js で自分で作るよりは楽そう
- テストが失敗したら最小限失敗するテストケースに縮退してくれるので、それを別のテストに切り出してデバッグするなどが便利
- 雑多なデータを突っ込んでみて自分でも思ってなかったとこを通すみたいな使い方がいいのかも?
- テストコード用のjsonとかをいちいち用意しておいて実装変わったからテストデータ用のjsonに大量の修正が必要になるとかは避けられそう。
参考
[TypeScript] Property based testing やってみる