「テストが無いコードはレガシーコードだ」と言われます。十分なカバレッジのユニットテストや E2E テストが用意されていて、それが常時 CI/CD で回っているというのは今時当たり前のことであって、とりたてて特別な環境ということもないでしょう。
しかし、テストが無い、もしくは不十分なコードに出会うことは多々あります。時間が無くてテストコードを書けなかったりとか、前任者から引き継いだらびっくりコードだったりとか、いろいろありますね。
そんなレガシーコードに出会ったとき、まず最初にどこから取り掛かろうかというのがこの記事です。どちらかというと、泥縄的、間に合わせ的なお話ですので、「正しいテストコードの在り方とは」といった話からは乖離しているでしょう。そういう記事をお求めの方は離脱していただくのが幸せかと思います。
なお、私自身がウェブ系の開発者なのでウェブ系を前提に記事を書いてますが、他の分野でも通じる話だと思います。
正しいけれど時間のかかり問題がある方法
テストフレームワークを導入して、手近なコードからユニットテストや E2E テストを書いていく方法です。もちろん CI/CD にも組み込みますから、仕組みとしては一気にモダンになります。
仕組みを用意できました。あとはテストコードです。時間があるときにみんなで少しずつテストコードを書いていきましょうとなります。よくある光景だと思います。
これ、手法としては正しいんですけれど、問題はテストが充実するまでの時間です。テストコードが充実して、テストによって障害を事前に防げるのって何年後の話でしょうか。テストコードが充実するまでの数年間、事実上テストなしの状態が継続してしまう問題はどうしましょう。
正しくないけどとりあえず役に立つ泥縄的方法
前述の正しいけれど時間のかかる方法に対し、正しくないし泥縄的だけどとりあえず役に立つ方法としてリクエストテストというものが考えられます。ウェブ系開発を前提にしているのでリクエストとレスポンスでテストする想定ですが、これは要するに統合テストのことです。
例えば Qiita の本番環境を対象にリクエストテストを書くとしたら以下のようになるでしょう。
#!/bin/bash
urls=(
"https://qiita.com/"
"https://qiita.com/question-feed"
"https://qiita.com/official-events"
"https://qiita.com/official-columns/"
"https://qiita.com/organizations"
)
for url in "${urls[@]}"; do
result=$(curl -s -I $url)
if [[ ! "$result" =~ "HTTP/2 200" ]]; then
echo "NG: $url"
echo "======"
echo "$result"
echo "======"
fi
sleep 0.1
done
サービスの主要なページに対して HTTP リクエストを送り、レスポンスのコードが 200 であるかどうかの検証だけを行っているテストです。
こんなテストであれば1時間もあれば用意できますよね。つまり、1時間後にはテストコードが無かったプロダクトにテストコードが出来上がるのです。何年も掛かってしまう正しい方法に比べると、圧倒的に速いですよね。
1時間程度で用意できるテストなのに、テスト対象のページに何か障害があってコケてしまう場合には検出が出来るようになるのです。これって便利ではないですかね。
もちろんリクエストテストには欠点もあります。
- 統合テストなので、テストがこけても障害個所の特定に手間がかかる。
- 簡単に書けるリクエストテストといえど、サービスの全機能を網羅するのは大変。
- ログイン機能や記事投稿機能など、複数ページに渡る挙動はテストしにくい。
- curl コマンドによるテストのため、フロントエンドの動作はテストできない。
欠点はあるのですが、とりあえずテストが無い状態を脱するということは実現できます。そこに価値はあるのではないかと思うのですが、いかがでしょうか。
まとめ
ということで、正しいけれど時間のかかる方法に対して、正しくないけれど即座に効果を表すリクエストテストという方法の提案でした。
リクエストテストはあくまでも応急処置であって、ユニットテストなどを書かなくていい言い訳ではありません。リクエストテストでとりあえず出血を止めている間に、きちんとしたテストコードを整備していくというのが適切なアプローチではないかと思います。