テストデータが dev 環境に見えてしまう — 面倒くさがって避けていた E2E の InMemory 化に踏み切るまで
E2E テストが共有の DB を叩くせいで、テスト用のダミーデータが dev 環境の画面に混ざる。Repository を抽象化して InMemory 実装に差し替えれば解決するのは分かっていたが、絶対に面倒だと踏んで先送りしていた。重い腰を上げた理由と、やってみた結果の話。
はじめに
テストをデータストアに依存させない、というのは設計の定石として何度も聞く話だ。自分もそう組んだ。ただ、踏み切った理由は「テストはこうあるべき」という原則論ではなかった。テストのダミーデータが、普段使っている環境の画面に見えてしまうのが嫌だったという、かなり生活感のある動機だ。
発端:共有 DB は「見えてしまう」
自分は検証環境を普段使いにしている。実装した機能が実際どう動くかを、その環境の画面で日常的に確かめる。
ところが E2E テストも同じ環境の DB を叩いていた。テストは当然テスト用のデータを作る。適当な名前、適当な金額、適当な日付。それが普段見ている画面にそのまま並ぶ。とくに資産・株価を扱うサービスでこれをやると、実データの中にテスト用のダミーが混ざって、見るたびに「これはテストのやつ、これは本物」と頭の中で仕分ける羽目になる。
CI から実クラウドのリソースを叩くこと自体のコストや認証の面倒くささも、もちろんある。だが自分にとって一番効いたのはそこではなく、検証環境が汚れて信用できなくなることだった。確認したくて用意した環境が、確認の邪魔をしてくる。これは順序が逆だ。
分かっていたのに避けていた
解決策の構想自体は前からあった。データストアへのアクセスを抽象化して、テストのときだけメモリ上の実装に差し替えればいい。よくある話だし、やるべきなのも分かっていた。
それでも手を出さなかったのは、絶対に面倒くさいと踏んでいたからだ。実装を一枚かませるだけでは済まず、既存のテストが軒並み動かなくなる予感があった。動いているものを触って、しばらく赤いままになる——その絵が見えていたので、優先度は下がり続けた。
天秤が傾いたのは、環境が汚れる不便さがその「面倒くさそう」を上回ったときだ。毎回データを見分ける小さなストレスが積み上がって、ある時点で「もういい、やる」となった。技術的な発見があって決断したわけではなく、単に不便さが閾値を超えた。
設計:差し替えられる形にしておく
やったことはシンプルで、データアクセスを Repository として抽象化し、実装を 2 つ持つ——DynamoDB を叩く実装と、メモリ上に持つ実装だ。どちらを使うかは環境変数のフラグで切り替え、生成はファクトリ側に寄せる。呼び出す側のコードは、どちらが挿さっているかを知らない。
肝は「テスト用の分岐をアプリ側に書かない」ことだ。if (テスト中) { ... } を業務ロジックに撒くと、テストのための分岐が本番のコードに住み着いてしまう。切り替え点をファクトリ 1 箇所に閉じ込めておけば、アプリのコードはテストの存在を意識しなくて済む。
この形にすると、副産物としてAWS に一切繋がずにテストが回るようになる。認証情報も要らないし、実リソースの状態にも左右されない。もともと狙っていたのは「環境を汚さない」ことだったが、結果的にテストの独立性まで付いてきた。
案の定、一発では終わらなかった
切り替えは想定どおり素直には終わらなかった。E2E が落ち続け、直しては別のところが落ちる時間がしばらく続いた。
なかでも厄介だったのは、メモリ上のデータが「どこから見るか」で分裂するという現象だ。同じプロセスの中でも、モジュールが別々に読み込まれると、それぞれが自分のメモリ上のストアを持ってしまう。データを書いたはずなのに、別の経路から読むと空。DB の中身を疑っても意味がなく、そもそも DB がひとつではなかった、という話だった。最終的にはインスタンスをプロセス全体で共有される場所に逃がして、どの経路から来ても同じ実体を掴むようにして解決した。
ただ、これで落胆したかというと、そうでもない。最初から沼る前提で始めていたからだ。「面倒くさいだろうな」と踏んで何度も先送りしていたくらいなので、実際に面倒だったのは想定の範囲内でしかない。覚悟して入った沼は、意外と精神的なダメージが少ない。
やってよかった
結論としては、やってよかったと強く思っている。検証環境にテストのゴミが積もらなくなり、画面に出ているものを疑わずに見られるようになった。「確認するための環境」がようやく本来の役割に戻った。
唯一の後悔は、もっと早く——というより最初から、メモリ実装との併用前提で設計しておけばよかったということだ。後から差し替え可能にするのは、既に動いているものを触る作業になる。最初からその形で書いていれば、追加コストはほぼゼロだったはずだ。
そして今回いちばん腑に落ちたのは、こういう改善を動かすのは往々にして正しさではなく不便さだ、ということだった。「テストは外部依存を持つべきでない」という原則は前から知っていて、それでは自分は動かなかった。動いたのは、毎日見る画面にダミーデータが混ざるのが嫌になったからだ。原則で腰が上がらないなら、その原則を守っていない状態が自分の日常をどう不便にしているかを数えてみるといい。そっちの方が、たぶん人を動かす。