自転車とプログラミング

元自転車メーカーのマーケター、今は自社開発企業に勤めるエンジニアが主にプログラミングの話を書きます。

『知識ゼロから学ぶソフトウェアテスト』を読んだまとめ

職場で開発者として自動テストを作りつつ、次工程にQAがいるのを不思議に感じてました。 開発者サイドで自動テスト書いてるのに人力でまたテストするの?みたいな状態です。

テストや組織体制の解像度を上げるため「知識ゼロから学ぶソフトウェアテスト」を読みました。

ではまとめていきます。

学びたかったこと

今回の本を読む上でのスタート地点として書いておきました。

  • テストの基準、何をテストして、テストしないのか
  • テスト対象に対してどうテストすると良いのか
  • 品質確保のテスト領域の全体像を知りたい

3つ目は本を読んでら途中から湧いてきた好奇心です。

ソフトウェアは十分複雑な工業製品である

タイトルの言葉はこの本の初めの方に出てきた言葉です。十分複雑なものであるからバグを取り切ることは不可能であると言い切っています。その上で品質を担保してプロダクトを出荷(リリース)するにはどうしたらいいか、というのがこの本が取るスタンスです。

そして企業にはリソースが限られるため「少ないテストで多くのバグを発見する」スキルを求められます。新人(スキルが低い人)がやるべき仕事ではないとも書かれていて私もそんな言葉を聞いたことがあったのですが納得しました。

テストの目的とは

テストの目的はバグを検出すること、そして検出したバグは解消されることになります。このサイクルの目的はプロダクトを充分な品質のもとでリリースすることにあります。

私は自動テストやTDDを中心に学んできてTDDは開発上の心理的安全性が高いとか、効率が良いみたいなことを聞いたりもしましたがそれらは副次的な話にすぎません。

きちんとした品質のプロダクトをリリースすることで自社の利益を得ること、バグ由来のリスクを低減させること、品質の高いソフトウェアで顧客からの信頼をあることなどが品質確保の目的です。

利益につながり、リスクヘッジになるからこそ企業はテストをしますし、QAという専門部隊も持つ訳ですね(全部自動化されてるとかも多いですが)

あと、必要品質はプロダクトによりけりなので企業によって品質を確保するためのテスト体制は異なります。

どうテストするのか

機能要件(ステークホルダーから求められるソフトウェアの機能)と非機能要件(パフォーマンスやセキュリティ、UIUXなどの機能以外の部分)、開発者が実施するのかQAが実施するのか、でテストの内容が違うようです。

そもそも、この書籍の初版はウォータフォール開発時代に出版されたものなのでCICDを活用したアジャイルな開発の場合は役割分担が薄いです。

また、仕様として決まっているものの動作を確認するテストの場合は、仕様そのものが誤りであることを検出できないので、正しいフェーズに正しい手法を選択していくことが品質を確保するテストでは求められます。

ホワイトボックステスト

処理の論理構造を確認するためのテストです。処理の実装に対するチェックをするのでインターフェースの中身まで明らかになる、ということでホワイトボックスと言われています。

主に単体テストと呼ばれる部分に該当しそうです。

制御パステスト

制御フローが問題ないかどうかのテストで、カテゴリーとしてはホワイトボックステストに含まれます。条件分岐や例外処理などの実装を確認していきます。

制御パステストで確認したコードの網羅率をカバレッジといいカバレッジテストとも言われています。

カバレッジはテスト品質の目安みたいなものです。高いといいですが、高ければ高いほどテストコストは上がるためカバレッジ80%くらいが目安になります。書籍で紹介されていたGoogleの指標では60%以上のカバレッジであることが最低限求められているようです。

正常系(分岐処理のtrueのみ)ばかりテストしていると自然とカバレッジは低くなりますのでfalseの処理フローもテストしていくことが求められます。

制御フローテストのイメージ 引用:https://webrage.jp/techblog/white_box_testing/

ブラックボックステスト

プログラムをブラックボックスに見立てて、インターフェースが正常なのか確認するテストです。こちらはホワイトボックステストと異なり実装を配慮しません。

境界値分析

ブラックボックステストに属するテストに境界値分析があります。処理が分岐する境界値をテストするものです。

条件分岐の境はバグが発生しやすい。条件ミス、誤字など、人的ミスに由来するものも多いです。

境界値テストは異なる処理が行われる最も近い値をテストする。中頃の値のテスト(同値分割法)の必要はないと言い切っているのはこの本の独自な感じがありました。確かに境界値のテストを通じて正常値のテストができていますので必ずしも必要ではなく、テストを増やす要因である、という主張には同意です。

境界値の例としては「二十歳以上への酒類提供」がわかりやすいと思います。

この場合は19歳以下と20歳以上が境界値になります。ここで分岐処理を書いたりするのでバグも出やすいです。間違って成人(18歳)以上にしたりとかね。

状態遷移テスト

アプリの状態とイベントからGUIの遷移を示し不意の動作をしないかのテストです。あるボタンを押したらAという動作(イベント)が発生するはずだ、という状態遷移をチェックします。

状態遷移テストを通じて期待していない動作や遷移そのものが発生しないバグを検知することができます。

オブジェクト指向ソフトウェアやGUI通信プロトコルといった状態の変化が明確な分野で活躍するテストです。

引用:知識ゼロから学ぶソフトウェアテスト

探索的テスト

ソフトウェア機能を学習しながら、テスト設計とテスト実行を同時に行う手法です。

テストケースを設定して行うテストよりも探索的テストの方がバグを引き出すことができるとのデータもでています。

過剰な値を入れる、開発者のコードの癖を考慮するなどバグを見つけるように探索しながらプロダクトに触るので仕様書通りのテストよりバグが見つかる。

なんなら探索的テストは通常のテストの弱点を示していて、テストケースを考えて作られるテストはテストケースを満たすことが目的になり得る、ということです。品質確保やバグ発見が目的ではなくなるためにテストそのもののクオリティが下がる可能性があります。そのあたり、探索的テストだとクオリティ低下の心配が少ないと言えるのです。

テストケースベースのテストと比較すると3〜7%くらい探索的テストの方が検出率が高いと言われています。

非機能要件のテスト

非機能要件とはパフォーマンスやUIUX、セキュリティなどの要求機能以外の分野です。テスト通じてこのあたりの品質を高めると、実際の使用感が良くなるので(ユーザーのニーズに沿っていればですが)ユーザー満足度があがります。

パフォーマンステスト

ソフトウェアはサクサク動くと嬉しいですよね。最近は意外ともっさりしたサービスも多いのでこの辺は実際にプロダクトを開発してる方からするとどうなんでしょう? 読書記録をつけてるNotionとかね。

パフォーマンステストをやるうえでは事前に、充分なパフォーマンスとは何かを設計前に定義することが必要です。それを実現するコードを書く。xxMBのデータをyy秒以内で処理する、といった感じ。

パフォーマンスの改善には設計の改善を伴う場合があり、大きな手戻りやコスト発生のリスクをともなうため、早めにテストしてバグを発見できると良いです。

パフォーマンステスト手順

  1. アーキテクチャバリデーション:アーキテクチャ的に想定通りのパフォーマンスを発揮するかのテスト
  2. パフォーマンスベンチマーク:部分的に出来上がったされたソフトウェアでベンチマークを測る
  3. パフォーマンス回帰テスト:開発段階のソフトウェアの変更に合わせて随時テストを行う
  4. パフォーマンスチューニング
  5. ユーザー環境でのテスト(24×7テスト)

セキュリティテスト

本書を読んでいて一番意外だったかもしれません。セキュリティテストの標準は未だないらしく、手法を研究して対策する形になるそうです。

バグが発生しそうな値を入力したり、想定外のアクセスができないかテストするようなものはあるそうですが、基本的にはハッカーがどんどん新手法を生み出すのをテストする側も研究してやってみる感じなんでしょうかね。このへんも定期的な学習が必要そうな分野です。

自動テスト

自動テストがデフォルトみたいなアジャイル全盛の現代ですが、本当に自動化の恩恵があるのか(人間より低コスト)という問いかけが目からウロコ。

コードを書けば負債になるとは良く言ったもので、書いた分だけ保守しなきゃいけないですし、CICDなどのテスト時間は増え続けます。人がやるのとどっちがいいんでしょうかね。

引用:知識ゼロから学ぶソフトウェアテスト

Googleはこの辺をふまえて高コストなテストは少なく、低コストの単体テストを多くするテストピラミッドを主張しています。和田卓人さんも言ってたやつですね。

実際に職場ではシステムテストは人力だったはず。コードよりも人が見たほうが探索的テストにもなるのでいいのかもしれません。

テストの運用

要求仕様

要求仕様とはこれから作るものの仕様をまとめたもの。要求をまとめない開発は完成定義がないためコストがとても嵩む。要求仕様がテストを作る上でも基準となります。

要求仕様を書くうえで、4つの大きな重要な要素が「漠然たるユーザー要求を機能要求に落とし込むこと」「要求に優先順位をつける」「テスト可能な要求を書く」そして「非機能要求」

引用:知識ゼロから学ぶソフトウェアテスト

要求仕様を書く時は、完全性、正当性、実現可能性、必要性、優先順位、曖昧さの排除、テスト可能性を満たしている必要がある。つまりはプロダクトとして実現できるもので優先順位がついててテストが可能ってこと。

ユーザーニーズを把握しているとピンポイントにニーズに合致したプロダクトを作れるように、要求と要求の依存関係を把握しておくとテスト効率が上がる

要求仕様で大事なことは開発でき、テストできる要求仕様じゃないと手戻りがあるということ。ユーザストーリーから要求仕様へ、そのままテスト仕様書にして開発者がTDDできるのが理想的。

品質のメトリクス

定量的に品質を計測する。計測する特定の品質をメトリクスという。

何を計測するのか?→バグの数が基本→バグの数を計測して信頼度成長曲線でソフトウェアの挙動が問題ないことを示すべき。指標は恣意的にいじれたり、ソフトウェアの品質を表現できないものはふさわしくない。

循環的複雑度(サイクロマチック)はプログラムの複雑さの目安であり、複雑だが高いとバグが出やすくなる。

目安は10、RuboCopは8が検出値。カーネギーメロン大学は10以上、筆者は20以上を要検出値としていた。

Microsoftのメトリクス

引用:知識ゼロから学ぶソフトウェアテスト

fourkeysメトリクスは開発者の生産性指標としてよく用いられる

  • デプロイ頻度
  • 変更リードタイム コミットから本番稼働まで
  • 変更障害率 本番でデプロイ要因の障害が起こる確率
  • サービス復元時間 本番環境の障害から復帰するまで?

感想

テストをどう書くか、という視点を超えて高品質なプロダクトを作れる開発者になりたいと思いました。引き続き頑張ります。