ホワイトボックステスト

記事
IT・テクノロジー

ホワイトボックステスト

前回紹介したブラックボックステストの対極にあるのがホワイトボックステストです。
ブラックボックステストはプログラムの内部を見ないで行うテストで、入力と出力(処理結果)でテストを行う手法でした。一方で、ホワイトボックステストは、プログラムの中身を中心に行うテストです。
プログラムの中身を中心にテストするため、プログラムの内部構造やフロー(処理の流れ)をよく理解していないとテストが難しいため、多くの場合、プログラムの設計者(コーディングした人)が行います。

基本的なコンセプトは?

ホワイトボックステストの基本的なコンセプトは、プログラムの全ての部分の動作を確認することにあります。
プログラムは条件によって処理方法を変えることが多く、ある条件で処理したときには実際には実行されない部分があるのが普通です。
例えばエラー処理が良い例ですが、エラー処理はエラーが発生した時だけ実行されます。 つまり、正常に処理されるケースのテストではエラー処理はテストされないことになります。ホワイトボックステストでは、意図的にエラーになる条件を作って、エラー処理を実行することでエラー処理が設計通りに動作することを確認します。

着目点は「if-else」や「switch」そして例外処理

ホワイトボックステストでテスト内容を考える場合に着目するポイントは、「if-else」や「switch」などの条件分岐の処理と、例外処理(try-catch)です。
プログラミングに使用するプログラミング言語によっても違いますが、これらの処理の流れを変える書き方は最近のプログラミング言語では似たものが多くなっています。
ホワイトボックステストの場合、どのように特定の部分のコードが実行される条件を作るかという部分がカギになります。
場合によっては、通常の処理では発生しないケースもあるので、デバッガーなどで値を操作してテストする場合もあります。
このテストはある意味「想定外」を減らすのに効果があります。テストそのものよりは、テストを考える際に、処理条件が抜けているのに気づく場合も多く、このテストの方針を考えることでプログラムの品質が向上します。
いろいろな条件で本来は別の処理をしなければいけないケースに、その条件が抜けていると、その条件の場合の動作が想定とは違ったものになります。ホワイトボックステストを意識してプログラムを書くことで、こうした「条件の抜け」を予防しやすくなります。

コーディングの時点でホワイトボックステストを意識する!

設計者が行うことが多いこのホワイトボックステストの検証をコーディング時に考えながらコーディングをすると、そうした細かい条件設定にも目が行くようになります。
大切なのは、このように「テストを意識してコードを書く姿勢」です。
テストを意識するとテストしやすいようにコードを書くようになります。そうすると、テストもやりやすく、コードに条件などの抜けが少なくなります。
当然実際にテストを行って、コードが正しく動作するかは調べるわけですが、テストを意識したコーディングはプログラムの品質確保に大きな役割を果たすと考えることができます。

プログラムの流れを追いかける!

ホワイトボックステストの一つの目的は、条件の抜けだけではありません。プログラム全体の処理の流れを確かめることも重要なテスト項目の一つです。
プログラムの流れを変える条件分岐や例外処理は一つではなく幾つかを組み合わせて処理の流れを作るのが普通です。この一連の流れが設計通りかを確認します。
実際は条件が抜けていると、この流れが途中で途切れる場合があります。これが、「想定外」での動作の問題です。この場合、処理が途切れているのでプログラムが固まる(フリーズ/ハング)する状態です。あるいは、処理のループから抜け出せずに別の処理に移行できない場合などがこれにあたります。

データの中身も見る

ホワイトボックステストのもう一つの目的は、データの変化を見ることも重要です。 プログラムの処理の流れが正しくても、データの処理方法に誤りがある場合には、処理結果は正しくなりません。
ブラックボックステストでは、入力データと出力データにのみ着目するのでその間は検証されません。ホワイトボックステストではこの中間の処理も含めてデータがどのように変化しながら処理されていくかも検証します。いわゆるデータフローです。

幾つかのパターンを考えて検証する

ホワイトボックステストでは、同じ処理の流れでも、データの変化は同じとは限りません。その辺を意識してテストする事が重要です。
例えば、数値の演算でよく起きる問題には、「オーバーフロー」や「アンダーフロー」、そして「0での割り算」です。処理の過程で数値の上限や下限を超えてしまったり、0での割り算が発生する場合がありますが、この場合は正しくエラーを検知してエラー処理を行うようにする必要があります。
これは、一連のデータ処理の流れでデータをチェックする機能をプログラムに持たせると防ぐこともできますし、予めそうしたエラーの処理をプログラムで実装する事が可能です。これも、テストを意識すると実際の実装で予め想定してその流れを設計に取り込むことができます。

ホワイトボックステストが難しいJavascript(Typescript)

ここまで、一般的なホワイトボックステストについて説明してきました。実は、WebサービスやWebアプリの実装でよく利用される、Javascript(Typescript)はこのホワイトボックステストが難しいプログラミング言語になっています。
これは、Javascript(Typescript)がシングルスレッドでの実行になるために、言語仕様として、非同期での実行を行うようになっているからです。
同期の実行では、プログラムでデータを処理する順番はプログラムの記述された順番が保証されるのでデータや処理の流れを追いやすいのですが、非同期で実行される場合はプログラムで記述された順番とは違った順序で処理が実行されるためです。
このあたりが、Webのソフトウエアの理解を複雑にしている要因です。
この非同期処理を少し見通し良くする手法が「ステート」と呼ばれる方法です。元々はハードウエアの設計ではよく利用される方法なのでハードウエアの知識がある場合には扱いやすいのですが、ソフトウエアは、順番に処理されるというイメージが強いためこの概念がわかりにくくなっています。
VueやReactがステートの概念を導入しているのはこうした、非同期の処理を扱いやすくするためです。
Firebaseやバックエンドのアクセスは非同期のアクセスになる場合が多く、その記述の仕方が検証やプログラムの不具合に大きく影響します。特に非同期の処理を、入れ子構造が複雑な書き方をすると予期しない問題が起きる場合があります。
最近の実装で問題になった例ですが、SendGridのAPIのアクセスを入れ子構造のプロミスで呼び出した時に、SendGridへのリクエストが、SendGirdが許容する間隔より短い間隔で送られたために「HTTPの429エラー」になったケースがありました。これは、「Too many request(リクエストしすぎ!)」というエラーで処理自体は論理的には正しいのですが、SendGrid側が処理しきれずにエラーになる場合でした。
このように、ブラックボックステスト同様に、ホワイトボックステストでも限界があります。
こうした問題は、コーディングの際に実際にどのように処理されるかを考えながら書くことである程度は防げます。しかし、非同期の処理は頭では負いきれない部分があるので、データの流れを追跡できるような仕組み(デバッグメッセージなど)を工夫することで検証を効率的に行う事ができます。

まとめ

ホワイトボックステストは、一般的に設計者(コーディングをした人)が行う、プログラムの中身の詳細を検証するテスト手法です。
WebサービスやWebアプリは非同期で動作する場合も多く、コーディングを工夫してホワイトボックステストを効率的に行うことを意識したコーディングが求められます。
非同期処理で発生する問題もデータの流れを終えるような形で実装しておくと問題が発生した場合でも効率的に原因を突き止めることができます。
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す