ベクターのツールで高品質のソフトウェアを作るための5つのビルディングブロック

後から保守リリースやパッチが公開されるのだから、最新バージョンのソフトウェアは避けたほうがよい―。それは経験から学んだユーザーの知恵です。大手企業ですら新規投入時のバグと無縁ではいられず、現に、携帯電話のソフトウェアのアップグレードサイクルでは、メジャーリリースの後に「フィックス」用の更新が何度か続きます。初期リリースと安定リリースの間にソフトウェア品質上のギャップがあることは紛れもない事実ですが、その解決は残念ながら進んでいません。

ここでは、開発グループがこの品質ギャップを埋めるのに役立つ、実行可能な5つのアイデアについて説明します。

1.テストカバレッジ

コードカバレッジ解析を使用する

コードカバレッジを解析すれば、一連のテストケースを実行してカバーされるソフトウェアソースコードの割合を知ることができます。コードカバレッジ解析はテストアクティビティーの完全性を測定する最善の方法であり、コードカバレッジを測定しなければ、テストの先を見通すことができません。

 

コードカバレッジ解析
図1 – コードカバレッジ解析によるテスト完全性の測定

「コードカバレッジ100%」を達成できても、そのアプリケーションが完璧である証明にはなりませんが、それが高品質のソフトウェアを作るための重要な要素であることは忘れてはいけません。事実、安全性を最重視するソフトウェアの開発に関わる標準規格はいずれも、コードカバレッジを開発プロセスの一環として義務付けています。


コードカバレッジの詳細については、こちらのホワイトペーパーをお読みください。

2.単体テスト

単体テストでテストカバレッジを改善する

図2 – 単体テストでカバレッジのギャップをなくし、100%のコードカバレッジを達成する

カバレッジを測定してみると、既存のテストでは100%を大きく下回る値しか達成できていないケースがほとんどです。 このようなカバレッジのギャップは、テスターが正常なユースケースにのみ注目し、エラーケースや境界条件を考慮していないのが原因です。

このギャップは新たに機能テストを追加すれば解消できるはずですが、アプリケーションコードのうち、一般に20%から30%はエラー処理のトリガーに必要なフォールトの注入が難しく、生産環境での機能テストでテストするのは非常に困難です。

フィールドで発生する深刻なバグは、アプリケーションに対して想定外の組み合わせで刺激が与えられた結果です。探索や切分けを試みると消滅したり、挙動を変えたりするハイゼンバグはその好例です。これらのバグは初期化していない変数が原因と考えられ、単にコードを観察するだけでは変更されているように見えるため、Cプログラマーの頭痛の種となっています[1]。

ここで威力を発揮するのが低レベルの単体テストです。単体テストではフォールトインジェクション、すなわち生産環境では不可能な方法でエラー処理をテストできます。
 

3.テストのインフラストラクチャー

テストを実行しやすく、結果を理解しやすくする

多彩なテストが含まれたテストピラミッド
図3 – 多彩なテストが含まれたテストピラミッド

「テストを実行しやすく、結果を理解しやすくする」のは、理屈だけ考えれば簡単そうですが、実際のところは必ずしも容易ではありません。これまで、さまざまなテストがさまざまな技術者によって、そしてしばしばさまざまなツールを使って構築され、維持されてきました。

  • 単体テストは、アプリケーションの低レベルのビルディングブロックの正しさを証明するために使用されます
  • サービスレイヤーテストとAPIレイヤーテストは、サブシステムが正しく機能することを証明するために作成されます
  • マンマシンインターフェイステスト(HMI)/機能テストは、エンドユーザーの視点からの正しさを証明するために作成されます

テストをこのように区分することにより、開発チーム全員でそれらを共有するのではなく、技術者グループごとにタイプの異なるテストを担当し、保守できるようになります。実際問題として、QAエンジニアが開発者のテストを実行したり、開発者がシステムテストを実行したりできる組織はほとんどありません。

品質を高めるには、開発チームの全員が、任意のテストを任意のタイミングで、任意のバージョンのアプリケーションについて実行できる必要があります。

このワークフローを可能にする鍵が、事前条件と期待される結果も含めてすべてのテストを収集する、テストのための共通のコラボレーションプラットフォームです。ここでは単独のテストの実行も、全テストの一括実行も、エンジニアがボタンをクリックするだけで実行できることが求められます。また、失敗したテストをスピーディーにデバッグできることも必要です。

詳しくは以下の文書をご覧ください。

Building a Flexible and Automated Testing Infrastructure

4.テストの効率

並行して実行できる、変更ベースの自動テストを実装する

コードカバレッジ解析でテストの完全性を高め、テストを組織全体に展開したら、次のステップはテストの迅速な実行を担保することです。テストを複数のグループで分担する理由の1つは、完全なシステムテストを実行すると、数時間から数日を要するためであって、コードを1行変更した開発者に10時間のテストを依頼すれば反発を受けるのは必定です。では、テストの完全性は確保しつつ、テスト時間を短縮するにはどうすればよいのでしょうか。

ここでの鍵は、拡張性の高いテスト用インフラストラクチャーを構築し、並行して実行できる、変更ベースのテストを使用することです。個々のテストはアトミックで小規模、しかも高速でなければなりません。新しいテストを既存のテストに単に挿入していった結果、テストスイート同士が強い関連性を持つようになってしまうことは少なくありませんが、そうなると堅牢なテストは望めず、テストの保守にも時間が掛かります。単純なことですが、テストを設計する場合には、他のテストの出力に依存しない、そのテスト独自の事前条件を定義すべきだということを頭に入れておく必要があります。

テストを再設計してそれらをアトミックに保てば、保守の面で有利になるだけでなく、以下も可能になります。

  • 変更ベーステスト。ソフトウェアの変更で影響があるテストのみを実行します
  • テストの並行実行。数百規模の個別のテストを同時に実行します

アプリケーションをインクリメンタルに自動ビルドしてくれるソフトウェアビルドシステムはどこも開発していますが、インクリメンタルにテストを実行するシステムが実装されているケースほとんどありません。テストは定期的に行われるのが一般的で、それが完全に自動化された形で、インクリメンタルに随時実施されることはまずないのです。変更ベーステスト(CBT)は、コードベースに加えられた一連の変更をそれぞれ解析し、それらの変更の影響を受けるテストのサブセットを、テスト全体の中からインテリジェントに選び出します。その結果、完全なテストを、そのフル実行に要する時間の数分の一で実行することが可能になります。また、変更ベーステストは、厳格な継続的インテグレーション(CI)開発プロセスを実装するための実用的な手段でもあり、CIのチェックインの際にCBTを使用することにより、効率的にビルドを検証し、問題を早期に検出することができます。

 

図4 –コード変更の影響を受けるテストケースのリグレッションテスト

テストのスピードをさらに向上するには、並行テストの実施を検討します。テストプラットフォームを継続的インテグレーションサーバー、そして仮想のテスト用マシンと統合することにより、テストの総所要時間を数時間から数分に、あるいは数分から数秒に短縮できます。

 

5.リファクタリング

コードベースをリファクタリングし、保守性を高める

図5 – コードのリファクタリングのアプローチ

コードのリファクタリングとは、アプリケーションの外部の挙動(API)は変えないまま、アプリケーションのコンポーネントを再構成するプロセスです。

リファクタリングを行わないと、アプリケーションのコードが非常に複雑化し、時間の経過につれて保守がしにくくなります。新機能やバグフィックスが既存の機能に追加された結果、当初の洗練された設計は見る影もない、といったことがよく起こるのです。

コードのリファクタリングはコードの可読性を改善して複雑さを軽減し、保守のコストも削減します。コードのリファクタリングをうまく行えば、基となるロジックを簡素化して無用な複雑化を排除でき、隠れたバグやまだ表面化していないバグ、見落とされているバグのほか、システムの脆弱性などの問題を解決できる可能性を高めることができます。

どのアプリケーションにも、開発者が既存の機能に影響が出るのを恐れて触りたがらない、バグが疑われる危うい箇所があるものです。そのような不安のあるモジュールを確実にリファクタリングするには、期待される挙動を正しく形式化したテストを構築するしかありません。

まとめ

30年以上もの間、ツール、設計パターン、開発パラダイムのシフトが連綿と続いてきました。これらの多くは、時間や手間を増やさずに品質を向上できることを謳っていますが、品質をコストをかけずに向上できる特効薬は現在も、そして将来も存在しえない事実を、今日のソフトウェア業界に関わる全員がよく理解しておかねばなません。ソフトウェアテストの効率を上げることこそが、ソフトウェア品質を向上するための唯一の現実解なのです。

--------------------

 

参考資料:

[1] Hristov, Ivan. Chasing Heisenbugs from an AKKA actor integration test with awaitility. 2012年9月16日。 honeysoft.wordpress.com/category/heisenbug/