安定してデリバリーするためのテストの取り組み

開発の小池です。入社して1年が経ちました。ツクリンクの開発、テストとリリースの改善をメインにやっています。

mogiの「ハンズシェア流スクラム開発の流れ」の補遺としてツクリンクの開発の中でテストをどんなふうにやってるのかを紹介する記事です。ツクリンクチームは、スプリントを固定し・スプリントを計画し・スプリントタスクをこなし・成果をレビューするというスクラムを半年ほどやってきました。その中で効率的かつ安定してリリースするためのテストのやりかたを模索していて、最近はこんな感じでやってます。

ツクリンク開発でのテストは大きく分けて次の3種類があります。

  • 実装時に記述する単体テスト
  • チケットごとにおこなう受け入れテスト
  • リリース前のリグレッションテスト

それぞれについて、いつどのようにテストを作って実施しているか書いていきます。

単体テスト

単体テストは RSpec で書いています。 RSpec はあまりに DSL らしくありすぎてクセが強いですが、モックやスタブ、マッチャが強力なので気に入っています。

ツクリンクはわりとファットな Model をもつ典型的な Rails アプリです。なので、 Model や Decorator の単体テストは全ての public なメソッドをカバーするように厚く書き、 Controller は Model のメソッドを適切に呼んでいるかを書くという基本方針でやっています。 View には極力複雑なロジックを置かないようにして、 Helper や Decorator がレンダリング時のロジックを吸収するようにしています。


カバレッジ: All: 71%, Controllers: 60%, Models: 87%, Mailers: 50%, Helpers: 68%, Libraries: 81%, Decorators: 70%, Validators: 96%, Serializer: 55%, Policies: 80%, Ungrouped: 100%

SimpleCov でとったカバレッジはこんな感じです。全体 71%は低いと評価するか高いと評価するか微妙なラインですが、私はそこそこ優秀な数字だと思います。Controller, Job, Decoratorは今後上げて行きたいとこですね。

受け入れテスト

受け入れテストは、ある変更が確かに実現されたかを確かめ、その変更の提案者に受け入れてもらうためのテストです。

ツクリンクのスクラムでは、プロダクトオーナーが新機能を提案し・デザイナが UI を設計し・プログラマがコードを書き・プロダクトオーナーが受け入れる、というモデルで開発を進めています。この流れはチケットを軸にして進められ、またチケットが開発に必要な全ての情報を持つように努めています。

つまり、あるチケットが実現されたかを確認できれば、その機能が実現されたことになります。モデル上ではプロダクトオーナーが受け入れるのが望ましいですが、チケットがちゃんと書かれていれば、受け入れテストは誰でも行なえることになります。

受け入れテストのテストケースは、基本的にはチケットのタイトルと同じになります。実際のチケットを見てみましょう:

チケットタイトル: 「プレミアム会員が自社情報編集ページでPR画像とムービーをアップロードする」、要件:...

これは前回(2018-11-16現在)のスプリントで開発されリリースされたチケットの実際のキャプチャです。ご覧の通り、チケットのタイトルはユーザストーリーとして書かれているので、正常系はこれを実現できればOKになるはずです。正常系にいくつかのパターンが存在する場合や、細かいステップ、前提条件、エラー時の挙動などは適宜記述します。

UI がシンプルな場合、受け入れテストの範囲は Controller の単体テストがすでにカバーしていることが多いです。 反対に複雑な UI を持つ場合は、 Controller の単体テストではカバーできない部分が出てきます。なのでこのテストは結合テストとしての役割も担っています。

リグレッションテスト

リグレッションテストはリリースの際にデグレード(既存の機能をぶっ壊すバグ)がないか確認することを目的にしたテストです。ツクリンク開発では、リリースは他の機能開発タスクと同じようにスプリント内の 1 タスクとして実施されます。だいたい 1 スプリントで 2 〜 3 回のリリースタスクが消化されます。

リグレッションテストでは、業務の要になる機能をユーザストーリーとして記述し、テストしています(本来はユーザがそのシステムでできることは全てテストするのが理想ですが、……)。リグレッションテストで使われるストーリーは毎回のリリースで同じものを使い、開発のなかでそれらのストーリーに変更があった場合、メンテナンスされます。また、受け入れテストの中で「これは業務の要になりうる」と判断されたものが追加されます。

銀の弾丸(にはならないけど…)

受け入れテストとリグレッションテストは手動でやるためコストが高いです。とくにリグレッションテストはくり返し何度もやっていくことになるのでなかなかたいへんです。

実際にブラウザを操作して動作の確認を行うことは機能を評価するうえでとても大切な工程です。しかし、長い期間くり返しやっていくと累計時間はどんどん増え・慣れや飽きは UI に対する適切な評価を下せなくし・また、精神もすり減ります。

それと、テストは開発が進むにつれてどんどん増えていきます。時間が無限にあるなら、今までに書かれた受け入れテストは全てリグレッションテストとしてメンテ・実施されるのが理想です。

そこで現在実ブラウザ(Headless Chrome + Capybara)をつかった e2e テストでリグレッションテストをちょっとずつ置きかえています。リグレッションテストが完全に自動化されれば、リリースはよりすばやく安定して行われるようになるはずです。受け入れた瞬間即リリースというフローを目指しています。

ただ、 e2e テストは e2e テストで結構辛いので、それについてはまた。

ハンズシェアではテストを書きまくりたい(もしくは全く書きたくない)プログラマを募集しています。