kkamegawa's weblog

Visual Studio,TFS,ALM,VSTS,DevOps関係のことについていろいろと書いていきます。Google Analyticsで解析を行っています

テストとテストデータ

テストの話第三弾。本日はテストとテストデータの話。推敲もせずに書いているので、突っ込みなどがありましたらどうぞ。

テストデータ

よく「手元の環境では性能の問題ないのに、本番では性能が出ない」とか「本番データ使うとテストケースから漏れている現象が発生する*1」とかありませんか?
データ件数は言うまでもなく、手元ではテストケースを満たすような数件〜あっても数百件程度のデータしかないため、今の機械ではデータベースのFULL-SCANが実行されても手元の検証環境では性能要件を満たしてしまうケースがあります。もちろん本番環境に持っていくと、性能が満たさないということで大騒ぎになります。
そうなると「チューニングで何とかしろ」という話になりますが、この場合の上の人が言うチューニングはたいてい「データベースサーバーやOSの設定変更で何とかしろ」みたいな感じですね。最悪「機械入れ替えればいいじゃない」みたいな話になりかねません。見事に赤字プロジェクトです。
テストデータを作ればいいじゃないかみたいな話もありますが、VBScriptPowerShellでつくるのもいいでしょう。私もよく作ります。でもそれだと「xx番目のデータ」とか、割と均一っぽいデータができたり、データの抜けが評価できなかったり(それは単体で評価されているはずという話もありますが)して、これまた「こんな本番データがあるなんて思いもしなかった」みたいな現象が出ます。私も「なぜ本番機で業務の一意制約違反なんて出るの?」と驚いたことがあります。
ちゃんと非NULLの項目は全部非NULLにしたようなデータしかないような状態なんてのもテストしましょう。きっと驚くような現象が出るかもしれません。
Visual Studioの場合、テストデータジェネレータが結構高機能です。もちろんもう少し何とかしてみたいなところもありますが、カスタムデータジェネレータでそれなりのデータが作れますので、一度試してみてください。
カスタム データ ジェネレーターを使用した特殊なテスト データの生成

計算量と性能

性能も重要なテスト項目の一つです。性能で重要なのは計算量と速度を区別しましょうということ。典型的な例では、DictionaryはO(1)という計算量である、つまり目的の要素を検索するためには一度の計算で済むと説明されています(実際はハッシュの衝突があるので常にO(1)ではありませんが)。
対してList(T)の場合、目的の要素を検索するには先頭から検索するため、O(n)(最悪の場合)という計算量になります。
この計算量は同じ環境で実行した場合、そのまま数倍する結果となります。たとえばO(1)の計算量の処理で1秒かかったとすると、O(n)では最悪n秒かかります。プログラムそのものを修正せず、O(1)と同じ時間で処理しようとすると、n倍の高速なマシンと入れ替えなくてはなりません。
プログラムを設計するときは難しいでしょうけど、実際にコードを書く、単体テストをするときはプロファイラなどを使って実行トレースをとって、計算量を計測しましょう。そして、計算量はできるだけ最悪のケースを想定する必要があります。もちろんテストでも最悪のケースを想定する必要があります。

*1:たいていは意図しないデータでの例外