AdventCalendar
テスト
単体テスト
adventcalendar2017

この記事はソフトウェアテスト Advent Calendar 2017の16日目の記事です。
昨日の15日目は、@Andysumiさんの「テスト管理ツールをいろいろ試してみた」です。
明日の17日目は、@nakanaoさんの「私がテスト計画を書く理由」です。

まえおき

初Qiita&Advent Calendarです。
私は、いわゆるSIerのウォーターフォール開発の下流工程を担当していました。
上流エンジニアの設計書を元に詳細設計、コーディング、単体試験をするお仕事です。

最近の私は、『動作確認』というなんだかよくわからない、そもそもテストなのか?と思うようなことしかしていなくて、テストの感覚がぬるくなった自覚があります。
そこで、昔を思い出すために、
昔の私が単体試験をする時、考えていたことをつらつらと書きだして行きます。

1.正しいことを証明できるか

1〜100の入力値を全部試験する?

1〜100までの入力を受け付ける画面があるとして、
その場合、「入力値に何を指定した試験をするか?」というお話。

私は、1〜100までの値を全部入れて、100回試験することはありません。
 
だいたい、境界値の-1、0、1、2、、、99、100、101を辺りと、
その他の数字を何個か、10、72辺りに入れてみよう、と私は考えます。

ただ、感覚では大丈夫だとは思うけど、
「それって試験したことになるの?58の時だけバグっていたらどうするの?」 
という疑問に答えられず、もやもやしていました。

そんな時に「プログラマのための数学」に出会いました。

プログラマのための数学

「プログラマのための数学」は、結城浩先生の本で、プログラマと関係する数学ネタの本です。
少し前に、第二版も出ました。
もうすぐ、第二版も出ます。
https://www.amazon.co.jp/dp/4797395451

本の詳しい紹介は省略しますが、
本の中で数学的帰納法について書れていました。

数学的帰納法

数学的帰納法について、詳しくはこちら

高校の時に数学で習いました。
ものすごく簡単にいうと、
 1、2、3、、、N、N+1 と1ずつ増えていく値について、
本当にそうなるよね?ということを、数学的に証明したい時に使える考え方です。

この本の「数学的帰納法」ついて書かれている章を読んで、
高校時代に学んだ数学ともやもやした感覚が結びついて、
それが数学的に証明できる!とわかって、もやもやが晴れました。

また、試験項目を考えている時の自分の感覚は、
数学の証明問題を解いている感覚に近い部分があることに気づき、共感がありました。

「プログラマのための数学」はそれ以外にもいろいろと面白くてオススメです。

2.組み合わせを考えるのお供

組み合わせの試験を考える時に、真理値表とベン図をよく使っていました。
学生時代にデジタル回路設計の勉強をしていたことがあり、
それがきっかけで使っていました。

真理値表

真理値表について、詳しくはこちら

真理値表は、こういう表です。

入力A 入力B 出力C
false false false
false true true
true false true
true true false

マトリクスや組み合わせ表、といった表現の方が伝わるかもしれません。
「こういう入力だと、こういう出力がある」
という組み合わせを表にしたものです。

ただし、組み合わせは、入力が増えると、指数的に倍に倍に増えて行きます。
そこで、増えすぎる組み合わせを、
試験ができる現実的な数にどう減らすかを考えることになります。

入力A 入力B 入力C 出力D
false false false false
false false true false
false true false true
false true true true
true false false false
true false true false
true true false true
true true true true

例えば、この表の組み合わせを減らすことができるでしょうか?

表をよく見ると、
出力Cの値が、入力Aと入力Bの値に関係なく、入力Aの値が決まることがわかります。
これで、入力Bを条件から減らすことができます。
このように、法則性を見つけて、減らしていきます。

ただ、入力が多くなると、表を眺めていてもなかなか気づきにくいことがあります。
それを考える時のアイテムのひとつにベン図が便利です。

ベン図

ベン図について、詳しくはこちら

私は高校の数学で習ったので、
同じく見たことある方も多いと思うのですが、
ベン図を使うことで視覚的に整理することができます。

入力A 入力B 入力C 出力D
false false false false
false false true false
false true false true
false true true true
true false false false
true false true false
true true false true
true true true true

先程のこの表もベン図を書いて見ると、すぐにわかります。

入力A 入力B 出力C
false false false
false true true
true false true
true true false

例えば、この表は、
入力Aと入力Bのどちらかだけがtrueであれば、入力Cがtrueになる
排他的論理和(XOR)です。
ただ、表を眺めているだけだと気づきにくかったりするのですが、
ベン図を書いて見ると、すぐにわかります。

ただ、同時に入力3つを超えると描きにくいため、不便な面もあります。

考える時のツール

真理値表、ベン図を使うと整理しやすくなります。
さらに、カルノー図、論理式、ブール代数などを使うことで、考える幅を広げられます。

ただし、やりすぎは危険です。
正規化と同じで、やりすぎると元々の形がわかりにくくなりますし、
変更に対してとても弱くなってしまいます。

また、現実的な仕事の中だと、
数学や論理的に証明できる範囲では減り切らずに、
組み合わせが膨大になってしまうことがあるため、
あくまで、試験を考える時のツール(道具)のひとつだと思って使います。

(組み合わせが膨大になる場合、例えば、直交表などを使って減らしたり)

3.ログを見る

障害解析時に使えるログになっているか

単体試験で試験しながらログを眺めます。
そして、障害解析時に使えるログになっているか?を考えます。

特に、ログレベルは大切で、DEBUGレベルだとエラー内容が出るけど、
運用時のINFOレベルでは、エラー内容が出ないことがあります。

本番環境で問題が起来た時に「ログ見てもわからない!」となるのは悲惨です。

「何が起きたか」がトレースできるログであることは大切です。
アクセスログや対向システムとの通信内容はできる限り、ログに残しておと障害解析に役立ちます。

匂いを感じる

ログを見ていると、「あれ?これ何かおかしい?」と不具合の匂いを感じることがあります。

ぼーっと見ているだけだと、気づかないこともありますが、
嗅覚を研ぎ澄ませてログを眺めていると、予期せぬ不具合に気づくことがあります。
じーっと一行一行を見ることもあれば、俯瞰することもあります。

4.どうすれば動かなくなるか?

単体試験を試験設計をする時は、「どうすれば動かなくなるか?」をひたすらに考えていました。

意地悪な入力

  • XSS、サロゲートペア、ディレクトリトラバーサル
  • 存在しないIDを入力
  • URLに直接遷移する
  • 必要なファイルを消しておく

途中で何が起きたら?

  • DBが再起動する
  • ネットワークが切れる
  • プロセスが落ちる
  • トランザクション中に例外が起きたら、ロールバックされる?

大量データ処理や連続実行をして大丈夫か?

  • レイテンシの低下、SQLが遅い
  • 処理輻輳
  • メモリリーク
  • マルチスレッド
  • 同時実行

設計や実装の難しい部分で、どういうところに設計や実装の穴があるか?

特に大切。システムの穴を探します。

  • 考慮が漏れそう
  • 処理のタイミングで矛盾が起きそう
  • 設計が難しそう
  • ソースコードを見ると怪しい
  • ログに気になるものが出ている
  • セキュリティ

例えば、状態を管理しているシステムでは、
処理の輻輳時に、想定外のステータス遷移をして想定外の動きをする、なんてことはあります。
人間が考えていることなので、もちろん穴があります。
思考が薄くなりやすいポイントを考えて狙いに行きます。

良いシステム?

以上のように、意地悪な試験をするために、考えていました。

背理法的証明の考え方に近いと思うのですが、
システムの正しい動きを考えるのではなく、
逆に、「システムはどうすれば動かなくなるか?」を考えて、
考え抜いた先に、何もなければ、それはきっと良いシステムです。
...というのは、さすがに強引ですね^^;

動きを把握しておく

システムを運用していくと、思いもよらないことは起きます。
ユーザが思っても見ない操作をしたり、サーバが落ちたり、様々です。
いわゆる正常系、ではなく、異常系、という動作は様々です。

試験をする過程で、
事前にシミュレートしておいたり、システムの動きを把握しておくことで、
何か起こった時に、
「これは見たことがある、あれかな?」と気付く、
「○○の時は××のように動くから、この仮説の可能性は低い」と切り分けの参考にできることがあります。

単体試験までに見つけたほうが良い

後工程や本番環境で問題が起きるといろいろと大変です。

異常系の処理は、アーキテクチャの見直しが必要なこともありますが、
開発工程が進むほど直すことは難しくなり、
偉い人への報告や水平展開にも追われてします。

また、一度本番環境で動いてしまえば、動くものを直すハードルはとても高くなります。

できるだけ、単体試験で見つけて直しておきたいものです。

まとめ

  1. プログラマのための数学」はオススメ
  2. 試験と数学の証明は近い部分がある
  3. 真理値表とベン図を考える時のツールに使う
  4. ログを見て匂いを感じとる
  5. どうすれば動かなくなるか?を考えて、穴を狙う

単体試験をする時に考えていたことを書いてみました。
書いた後に気づきましたが、まとまりがない内容になってしまいました。
(それにしても、昔は今と比べてちゃんと単体試験してたな...)

ここまでお読みいただきありがとうございました。