こんにちは。QAエンジニアをしているharashinです。
freeeプロダクト共通で利用される従業員情報や取引先などのマスターデータを扱うプロダクトを担当しています。
freee QA Advent Calendar2024 1日目です。
去年に引き続き、QA Advent Calendar2024の発起人です。
今年も無事QAエンジニアだけでアドベントカレンダーを実施できることを大変うれしく思います。
去年のアドベントカレンダーを実施するにあたり、多くの方に圧をかけた結果、社内ではharashin とハラスメントがかけ合わさったハラシンメントという造語が作られました。
今年は、「テストレシピをやってみた」というタイトルでアドベントカレンダーを書いてみようと思います。
チームのQAに関する課題感
課題感は大きく2つのありました。
- QAがボトルネックになっている
- 継続的なテストができていない
QAがボトルネックになっている
開発チームがQAEのアサインができていない時期や、QAEのアサインが十分ではなく、QAの工程はWF開発になっており、開発が完了してからテストを実施するため、QAがボトルネックになる状況でした。
継続的なテストができていない
EngとQAEがお互いのテストの内容の共有ができておらず、チームとしてどのようなテストを実施しているか不明確な状況でした。
またQAEが実施するテストケースは一度きりの手動でのシステムテストであったり、継続的なテストをしていく上でチームでのテストの全体量もわからず、どのようなケースを継続的にテストしていくべきかも不明確でした。
どのように課題にアプローチするか
過去、チームではQAEがいなくなった時期にEngがQAEが用意していたテストケースを実施したことがありました。 その際にEngがユニットテストと重複したテストケースが多いと気が付きました。
そこで、実はQAEがテスト設計しているテストケースをEngに共有することで、ユニットテストとシステムテストの重複を減らすことで、QAのボトルネックを解消できるのではないかという仮説を立てました。
またテストの重複を減らすだけでなく、ユニットテストを増やしていくことで継続的なテストが可能になるのではないかと考えました。
今回は、テストピラミッドなどのあるべき理想の提示ではなく、まず開発プロセスの中で、テストレベルの最適化に向けて一歩目としてどういうことに取り組んでみたかというのを書いていきます。ユニットテスト・インテグレーションテスト・システムテストの厳密な定義については今回は触れません。
兎にも角にも、一歩目としてテストケースをEngに共有しないと始まらないと思い、テストレシピを導入してみました。
テストレシピとは
テストレシピとは、The Art of Unit Testingという書籍の中で記載されているもので、テストレベルのバランスを適切にするために、シナリオを元にEngとQAEで話し合い、どのテストレベルでテストを行うか決めていくこと。(解釈間違ってたらごめんなさい)
初めから参考にしていたわけではなく、進めていくうちにEngが読んだ書籍のなかで似たような取り組みをしているねという話になり、「テストレシピ」という名前をつけて取り組んでいくことになりました。
個人的にスクラムでの受け入れ条件と近い印象があり、受け入れ条件にさらにテストレベルを付与したようなものと捉えています。
やったこと
- 開発チケットの粒度でテストケースを設計し、Engに共有
- 共有のタイミングは、朝会の後にちょっとずつ共有/実装が始まる前
- テストケースを元に、リグレッションテストとして見るべきか/どのテストレベルで実施するかを決める
方針として、リグレッションテストとして含めるテストケースは自動テストにしていくことにしました。
テストレシピは、テストケースを共有していく中で議論したメモやコメントが追加がしやすいように、Googleドキュメントに書いていくことにしました。
テストレシピは確定していないテストケースとして扱い、そのままテスト管理として使うことはせず、 共有して話し合った結果、確定したテストケースを、テスト管理ツールに格納して進捗を管理することにしました。
進め方
開発着手前(EngとQAE)
- テストケースを設計
- 開発チケットの粒度で、テストケースを共有
- テストケースを元にどのテストレベルで実施するかを決める
開発中(Eng)
4 . チケット実装に着手するタイミングで、テストも実装
開発終了後(QAE)
- チケット開発完了後、システムテストを実施
進め方(QAE視点)
1. テストケースを設計
これまで私がしてきたテスト設計は、テストチャーターで行っていたため記載内容を粗めに書くことが多くありました。そのままEngに共有すると理解しずらい・解釈に幅を持たせてしまうテストケースがありました。 なので、できるだけ細かなテストケースの粒度を記載するように心がけました。
今回はマイクロサービスの機能開発も多くあったので、 事前にgRPC のインターフェースの情報やシーケンス図などを利用することでプロダクトの機能の責務を明確することで、テストケースを細分化していきました。
2. 開発チケットの粒度で、テストケースを共有
開発チケットに対して、テストケースを共有することで追加のテストの話になったり、仕様で詰めきれていなかった部分も合わせて確認することができます。
この段階で重篤度の高い事象が起こる可能性がある機能に対するテストケースに対して、認識を合わせました。 そのテストケースが失敗したときに、起こる事象が重篤度が高いどうかで、テストケースについても重篤度と同じ概念(major,normalなど)を付与しました。 speakerdeck.com
よりわかりやすくいうと、リスクベースドテストを行うために、EngとQAEで認識を揃えるために実施しました。 ただテストケースの実施の優先度を決めるだけではなく、リグレッションテストとして実施するテストケースを決めるためにも実施しました。 (以降は、テストが失敗したときに重篤度が高い事象が起こる可能性が大きい機能に関するテストケースを、重篤度の高いテストケースを呼びます。)
たとえば、バリデーションの確認は、マスターデータを取り扱うチームとしては、 バリデーションが機能していないとデータ不整合を招く可能性があるため、バリデーションは重篤度の高いテストケースとしてmajorとしました。
重篤度の低いテストケースは、一度テストとして実施はするが、リグレッションテストとして実施せず、 重篤度の高いテストケースに対しては、今後リグレッションテストとして実行していくという認識を合わせました。
3. テストケースを元にどのテストレベルで実施するかを決める
共有したテストケースに対して、どのテストレベルで実施するかを決めました。 ユニットテスト・インテグレーションテスト・システムテストで担保するかを決めました。
さらにテストレベルとの組み合わせで、先ほどのバリデーションのテストケースだと ユニットテストでのバリデーションチェックは重篤度が高いテストケースだが、 システムテストでのバリデーションチェックはエラー文言などのユーザビリティに関する確認なので重篤度が低いテストケースとしました。
またドメインロジックに関する機能は、 ユニットテストなどで細かなロジックのテストを行い、システムテストでは一連のデータフローのテストをしたり、一つの機能に対してすべてのテストレベルで重篤度の高いテストケースすることもありました。
テストレベルと重篤度のような概念をテストケースに付与することで、リグレッションテストを明確にしていきました。
5. チケット開発完了後、システムテストを実施
着手可能になったチケット・機能から、システムテストを実施した。先ほど決めた重篤度の高いテストケースから優先的にテストを実施していきます。
チケット単位でのテストを実施しているため、開発がすべて完了したあとにデグレが起きてないか心配になることがあるが、 重篤度の高いテストケースをリグレッションテストとして実施することで、デグレがないことを確認しました。
やってみてどうだったか/課題に対してどうだったか
初めの一歩として、とりあえずテストケースを同期的にEngに共有するというアクションは、 Engにテストケースの内容を知ってもらうことができたので、とても良かったと感じました。
チームで重篤度を用いてリスクに対する認識を揃え、そこに対するテストが書かれていることで安心感を持って開発が進められました。
またテストレシピを共有をまとまった時間でやるのではなく、 日々朝会などで共有することで、テストについて話す・考える時間をチームで日常的に持つことができ、 開発が進んでいくなかで発生する仕様変更であったり、新たなリスクに気が付くための機会が増えたと感じました。
『課題:QAがボトルネックになっている』に対して、どうだったか
システムテストの割合は減りました。最初の設計時のテストケースの全体からシステムテストの割合は約1/3程度でした。(テストケースの粒度の違いはあるのであくまで目安)
さらにドメインロジック周りなど重篤度が高い事象が起こる可能性の高い機能に関して、テストをEngがユニットテストで担保することで全体を通して重篤度の高いバグがほとんどありませんでした。
『課題:継続的なテストができていない』に対して、どうだったか
開発終了時点で、リグレッションテストにするテストケースがすでにあり、多くがユニットテストやインテグレーションテストなので、自動テストになっていました。 システムテストの割合が減ったため、E2Eテストに実装するべきシナリオも少なく済んだので、継続的なテストができるようになっていました。
またアジャイル開発の中で、すでにリグレッションテストとしてやるべきテストケースをチームで決めていたので、すべての開発終了後にリグレッションテストを実施することでデグレの懸念も解消されました。
むずかしかったところ
テストレシピの共有の仕方
今回できるだけ細かなテストケースの記載を心がけたが、実際にテストレシピで話したテストケースと実装されるユニットテストの粒度が異なってしたので、 Engの解釈に委ねる部分があると感じたので、まだまだテストケースの共有の仕方については改善の余地があると感じました。 QAEがユニットテストやシステムへの解像度を高くすることで、テストケースの共有の仕方も変わってくると思うので、今後の課題として取り組んでいきたいです。
実装が始まる前に、テストレベルの細かいところまで決めきれていなかった。
ユニットテスト〜システムテストというざっくりしたテストを決めることで、課題が解消されたことは良かったが、 チームで取り組みをスケールさせていくためには、どの層でどのようなテストをしていくかのプロダクトにあった細かなテストガイドラインは必要だと感じました。 チームでテストガイドラインを作成し始めたので、運用していく中で設計前からでも確度を高くテストレベルを決めていけるようにしていきたいです。
次回予告
明日は、グローバルQAエンジニアチームのQAエンジニアのyamaeri-san が「グローバルQAエンジニアチームのマネージャーになってみた」について記事を書いてくれます。お楽しみに〜!
それでは、みなさん
良い品質を〜!