検定フレームワークを使う
検定フレームワークを使う
test = VerificationTest[2 + 2, 4]TestCreateは検定を作成するだけですぐに実行はしない:
test = TestCreate[2 + 2, 4]検定を実行するためには,TestEvaluateを使う:
TestEvaluate[test]TestCreateは実際の検定を実行しないので,検定の作成はすぐにできる:
AbsoluteTiming[tests = Table[TestCreate[Pause[1];2 + 2, 4, TestID -> i], {i, 4}]]AbsoluteTiming[Map[TestEvaluate, tests]]長い検定をスピードアップするためにはParallelMapが使える:
AbsoluteTiming[ParallelMap[TestEvaluate, tests]]このセクションではTestCreateとVerificationTestの主な違いを見てみる.可能な限り検定はTestCreateを使って定義した方がよい.作成と評価を分けることで,次のようないくつかの機能が利用できる:
TestCreateを使って検定を作成する場合,入力式に含まれるシンボルはどれも評価されない.次の検定を見てみる:
a = 2;
test = TestCreate[a + 3, 5]test["Input"]TestEvaluate[test]Clear[a];
TestEvaluate[test]大域的な依存性を避けるために,With等を使って検定に静的値を挿入することができる:
test = With[{a = 2}, TestCreate[a + 3, 5]]test["Input"]expr = NumericArray[Range[10]]output = Export[CreateFile[], expr, "WXF"]result = Import[output, "WXF"]result == exprTestEvaluate @ TestCreate[
Import[Export[CreateFile[], NumericArray[Range[10]], "WXF"], "WXF"],
NumericArray[Range[10]]
]tests = TestEvaluate @ {
TestCreate[
output = Export[CreateFile[], NumericArray[Range[10]], "WXF"],
_String ? FileExistsQ,
SameTest -> MatchQ,
TestID -> "my-test-export"
],
TestCreate[
Import[output, "WXF"],
NumericArray[Range[10]],
TestID -> "my-test-import"
]
}Last[tests]["Input"]test = TestEvaluate @ TestCreate[
With[
{output = IntermediateTest[
Export[CreateFile[], NumericArray[Range[10]], "WXF"],
_String ? FileExistsQ,
SameTest -> MatchQ,
TestID -> "my-test-export-stage"
]},
Import[output, "WXF"]
],
NumericArray[Range[10]],
TestID -> "my-test-import"
]test["IntermediateTests"]IntermediateTestが失敗すると外部検定も失敗するので,検定についての全体的な結果1つ得られる.外部検定内のIntermediateTestの結果を調べると,外部検定のどのステップが成功してどれが失敗したかが分かる.
TestReportはいくつもの目的を果たす1つの関数である.
TestReportを使って検定を実行する
TestReportは複数の検定を実行するために使うことができる:
TestReport[{
TestCreate[Sin[E] > Cos[E]],
TestCreate[MatrixQ[{{1, 2, 3}, {4, 5, 6, 7}}]], TestCreate[1 / 0, ComplexInfinity]
}]tests = {VerificationTest[Echo[1 + 1], 2], TestCreate[Echo[2 + 2], 4]}TestReport[tests]TestReportを使って検定結果を結合する
r1 = TestReport @ Table[TestCreate[RandomInteger[], 1], 4]
r2 = TestReport @ Table[TestCreate[RandomReal[], 0.5, SameTest -> Greater], 12]r3 = TestReport[{r1, r2}]結果を結合すると,TestReportは自動的に重複したものを削除する:
TestReport[{r1, r1, r2, r2, r3}]TestReportを使って評価せずに検定を集める
file = Export[
CreateFile[],
Unevaluated@{TestCreate[Echo[1], Null], TestCreate[Echo[2], Null]},
"WL"
]ファイル上でTestReportを実行すると,評価されていない検定がデフォルトではすべて評価される:
report = TestReport[file]IdentityをTestEvaluationFunctionとして使うことによって,TestReportに検定を収集するだけで評価はしないよう指示することができる.検定は実行していないのでこの操作はずっと速い:
report = TestReport[file, TestEvaluationFunction -> Identity]tests = #["TestCreate"]& /@ report["Results"]HoldFormを解放することで検定オブジェクトを再構築することができる:
Map[ReleaseHold, tests]TestReportが行っていることのロギングはコードをデバッグするために必須のことである.実行中のある点で失敗する可能性のある長い検定一式を生成する:
tests = Table[
TestCreate[Pause[1]; If[RandomReal[] <= 0.2, Throw[i]], Null, TestID -> i],
{i, 10}
];TestReport[tests]失敗している検定すべてをリアルタイムでログするためにはHandlerFunctionsを使うことができる:
TestReport[
tests,
ProgressReporting -> False,
HandlerFunctions -> <|"TestEvaluated" -> Function[If[#Outcome != "Success", Echo[#TestObject, "😵"]]]|>
];TestReport[
Table[TestCreate[RandomInteger[], 1], 3],
ProgressReporting -> False,
HandlerFunctions -> <|"UnhandledEvent" -> Echo|>
];Catch @ TestReport[
Table[TestCreate[RandomInteger[], 1, TestID -> i], {i, 20}],
HandlerFunctions -> <|
"TestEvaluated" ->
Function[If[#Outcome != "Success", Throw[#TestObject]]]|>
]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を割り当てておくとよい.