検定フレームワークを使う

Wolfram言語はコードを書き,その検定を実行するためのフレームワークを提供する.
検定を定義するための主な関数としてVerificationTestTestCreateがある.
VerificationTestはWolfram言語のために作成された最初の検定関数である.その動作は単純である.検定はすぐに評価されTestObjectが返される:
TestCreateは検定を作成するだけですぐに実行はしない:
検定を実行するためには,TestEvaluateを使う:
TestCreateは実際の検定を実行しないので,検定の作成はすぐにできる:
これで検定を評価する.休止は順に評価される:
長い検定をスピードアップするためにはParallelMapが使える:
このセクションではTestCreateVerificationTestの主な違いを見てみる.可能な限り検定はTestCreateを使って定義した方がよい.作成と評価を分けることで,次のようないくつかの機能が利用できる:
変更不可能な検定を書く
TestCreateを使って検定を作成する場合,入力式に含まれるシンボルはどれも評価されない.次の検定を見てみる:
TestObjectにシンボル a への参照が含まれている.そのシンボルは定義されているので,TestEvaluateを実行すると検定は動作する:
しかし,故意でも偶然でも a の定義を消去すると検定は失敗する:
大域的な依存性を避けるために,With等を使って検定に静的値を挿入することができる:
これで"Input" 特性にもとのシンボルの参照が含まれていないことが確かめられる.これによって検定は完全に独立して実行される:
複数ステップ操作のための検定を書く
ライブラリの検定を行う場合は,より複雑な使用事例を検定するのに1つの検定では不十分なことがある.
例えば,Exportによって生成されたファイルがImportにとって可読であり.式が最初のものと同一であることを確認する検定を書いてみよう.
そのような操作を一連の検定に変換する一つの方法として以下がある:
この検定の問題点は,異なる理由で失敗する可能性のある2つの操作(検定データのExportImport)を組み合せているということである.これを複数の検定に分けることもできる:
この方法の欠点は,2番目の検定が最初の検定と絡み合っているため,検定の原子性を破っていることである.検定の"Input"特性には output という名前の大域変数への参照が含まれている.
つまり,最後の検定だけを別に実行したり,別の検定で同じシンボルを使ったりするときに,output の値をたまたま変更すると検定は失敗し始めるということである.
よりよい方法はIntermediateTestを使って検定を分割することである.結果のTestObjectの中のをクリックすると検定の中間結果を見ることができる:
この検定は自己完結型であり,常に単独で実行できる.中間検定の結果は別々に調べられる.
IntermediateTestが失敗すると外部検定も失敗するので,検定についての全体的な結果1つ得られる.外部検定内のIntermediateTestの結果を調べると,外部検定のどのステップが成功してどれが失敗したかが分かる.
TestReportを使う
TestReportはいくつもの目的を果たす1つの関数である.

TestReportを使って検定を実行する

TestReportは複数の検定を実行するために使うことができる:
TestReport"NotEvaluated"検定だけを実行する.つまり,すでに評価された検定のリストがある場合,すでに評価されたものは評価しない:

TestReportを使って検定結果を結合する

TestReportは複数のTestReportObjectを結合することができる.2つのオブジェクトを生成する:
以下のようにするとレポートを結合することができる:
結果を結合すると,TestReportは自動的に重複したものを削除する:

TestReportを使って評価せずに検定を集める

いくつかの検定式をファイルにエキスポートすることで検定ファイルを作成する:
ファイル上でTestReportを実行すると,評価されていない検定がデフォルトではすべて評価される:
IdentityTestEvaluationFunctionとして使うことによって,TestReportに検定を収集するだけで評価はしないよう指示することができる.検定は実行していないのでこの操作はずっと速い:
検定の収集は検定式を再作成したり記号的に操作したりする場合に便利である."TestCreate"特性はもとの検定式をHoldFormにラップして再構成する.
HoldFormを解放することで検定オブジェクトを再構築することができる:
デバッグとTestReportのロギング
TestReportが行っていることのロギングはコードをデバッグするために必須のことである.実行中のある点で失敗する可能性のある長い検定一式を生成する:
検定一式を実行すると進捗インジケータが表示される.ほとんどの場合これで十分であるが,必要な情報すべてはリアルタイムで表示しない.
失敗している検定すべてをリアルタイムでログするためにはHandlerFunctionsを使うことができる:
イベントの完全リストはTestReportのドキュメントで見ることができるが,"UnhandledEvent"を使うとTestReportが行っていることをすぐに見ることができる:
TestReportの制御フローを破る
HandlerFunctionsを使うと,検定が失敗したときにすぐに失敗するカスタムのTestReportを書くことができる:
検定ファイルを書く
TestReportの検定ファイルを書くことは,通常単純な操作である.検定ファイルの最初で必要なコンテキストをロードするだけである:
Needs["MyContext`"]

TestCreate[MyContext`AddOne[1], 2, TestID -> "MyContext-AddOne-Test"]
TestCreate[MyContext`AddTwo[1], 3, TestID -> "MyContext-AddTwo-Test"]
TestCreateに含まれないコードはすべて,検定を実行していないとしても検定ファイルがロードされたときに毎回実行される.検定ファイルは検定のリスト,またはプログラムで検定を作成する式を含むことができる:
Needs["MyContext`"]

Table[
    TestCreate[
        MyContext`AddOne[i],
        i+1,
        TestID-> "MyContext-AddOne-" <> IntegerString[i]
    ],
    {i, 1, 20}
]
それぞれの検定に意味のあるTestIDを割り当てておくとよい.