dynamodbのローカルサーバーを使ったテストでも並列実行を諦めない
tl;dr
dynamodbへアクセスする自動テストを並列で実行するためにvitest-dynamodb-liteというライブラリを公開した。
背景
一般に、dynamodb-localを用いてテストを行う場合、それぞれのテストケースが競合を起こさないように以下のどちらかの方法を選ぶ必要があります。
- a. それぞれのテストケースで異なるitem keyを使うようにする
- b. 並列実行を諦める
aは気をつけているつもりでも時々flakyテストを生み出してしまいがちです。また、scanを用いるバッチなどの処理ではkey重複避けすることができません。
bは単純にテストが遅くなります。
また、テスト実行前にdockerなどを用いてdynamodb-localをあらかじめ起動しておく必要があります。 この起動を忘れてテストを実行してしまうくだらないミスが一人当たり毎秒5億回、発生していると言われています(著者調べ)。
このミスを無くしたい。key競合のflakyなんか気にしたくない。並列実行も諦めたくない。
解決策
vitest-dynamodb-liteというライブラリを公開しました。
まずはこちらのgifを御覧ください。
上記のgifでは、16個のテストファイルをvitestを使って16並列でテストしています。それぞれのテストケースは同じ名前のdynamodbテーブルの同じitem keyに対して操作を行っています。
vitest-dynamodb-liteではvitestの並列workerごとにdynamodbのローカルサーバーを立てているため、worker間で競合が発生することがありません。
dynamodbローカルサーバーにはDynamoDB Localではなくdynaliteを使っています。
そのためworkerごとにローカルサーバーを立てているとは思えない速さでテストが完了します。
dynamodb-localは処理速度は申し分ないけど、起動が遅すぎて今回のような解決策には向きません。(dynamodb-local, localstackがrustでreplaceされる日を夢見てる)
作成にあたって
このライブラリは基本的にjest-dynaliteをフォークして作成されています。
dynaliteを使うアイデアも、workerごとに起動するアイデアも、僕が考えたものではなくフォーク元のリポジトリがもともと持っていたアイデアです。
僕はこれについて
- rewrite for vitest
- rewrite to ts
- performance improvement
を施しました。
performance improvementの結果、vitestで実行されるアドバンテージ以上にパフォーマンス改善されています。(テストケースごとに-4秒程度)
まとめ
僕は自動テストが好きです。特にファイルをwatchしてファイル変更都度、即座にgreen/redを教えてくれる自動テストが好きです。
Googleが提案するTest Sizeにおいて、例ではSmallサイズのテストは「60秒以内で終わる」「DBアクセスはしない」となっています。
でも、「60秒以内で終わる」なら、DBアクセスしたっていいじゃない。
以上、やまたつでした。