gauche.test
- 単体テスト ¶テストスクリプトを書くための手続きを提供します。 テストスクリプトは次のような形になります。
(use gauche.test) (test-start "my feature") (load "my-feature") ; テストすべきプログラムをロード (import my-feature) ; モジュールを定義している場合はインポート (test-module 'my-feature) ; モジュールの一貫性チェック (test-section "feature group 1") (test "feature 1-1" EXPECT (lambda () TEST-BODY)) (test "feature 1-2" EXPECT (lambda () TEST-BODY)) ... (test-section "feature group 2") (define test-data ...) (test "feature 2-1" EXPECT (lambda () TEST-BODY)) (test "feature 2-2" (test-error) (lambda () TEST-THAT-SIGNALS-ERROR)) ... (test-end :exit-on-failure #t)
このテストスクリプトは、バッチ処理でもインタラクティブセッションからでも 実行できます。インタラクティブセッションの場合はこのテストスクリプトを ただロードすれば、各テストの結果とサマリーが報告されます。 バッチテストの場合は、標準出力を別のファイルにリダイレクトしておくと良いでしょう。 標準出力が端末でない場合、テスト手続きは詳しい結果をstdoutに出力し、簡単な メッセージを標準エラー出力に書き出します。
モジュールやプログラムを書いたら、Makefileに"check"ターゲットを作ることを お薦めします。ルールはこんな感じになるでしょう:
check : gosh my-feature-test.scm > test.log
ポータブルなコードでは、テストフレームワークを定めたsrfiがあります
(srfi.78
- 軽量なテスト、およびsrfi.64
- SchemeテストスイートAPI参照)。
Gaucheでは、これらのsrfiをgauche.test
と一緒に使うと、
srfiのテストがGaucheのテストとして走るようになっています。
• テストファイルの構造: | ||
• 個々のテスト: | ||
• 外部のテストの取り込み: | ||
• 見やすいテスト失敗の報告: | ||
• 準静的検査: |
{gauche.test
}
テストの状態を初期化して、ヘッダをログに書き出します。テストを呼ぶ前に呼んで下さい。
module-nameはログのために使われる文字列です。
テストが既に走っている場合は、
この手続きはログメッセージを出して内部のテストネストレベルを更新するだけです。
これにより、test-start
/test-end
のペアを持つスクリプトを
別のテストスクリプトからincludeすることができます。
この機能は、例えば長大なテストスクリプトをいくつかのサブテストスクリプトに 分割するのに役立ちます。各サブテストスクリプトはそれぞれ独立に走れるように しておいて、元のテストスクリプトはそれらをincludeします。 これによって、開発中は必要なサブテストスクリプトだけを走らせ、フルテストでは 全てのテストを走らせる、といった運用ができます。
{gauche.test
}
失敗したテストのリストを報告します。exit-on-failureが#f
か
省略された場合は、この手続きは失敗したテストの数を返します。
そうでなければ、この手続きはexit
を呼んでgosh
を
終了させます。exit-on-failure
にfixnumが渡された場合は、
それがプロセスの終了ステータスとして使われます。exit-on-failure
が
他の真となる値であった場合は、終了ステータスは1となります。
テストがネストしている場合、つまりこのtest-end
と対応するtest-start
が、既にテストが走っている状況で実行されていた場合は、この手続きは単にログメッセージを
出力して内部のテストネストレベルを調整します。
{gauche.test
}
テストが実行中、つまり、一番外側のtest-start
とtest-end
の間に
いるならば#t
を、そうでなければ#f
を返します。
{gauche.test
}
一群のテストの開始をマークします。単にログに使われるだけです。
{gauche.test
}
この手続きも単なるログのためのものです。
format
と同じようにfmtstrとargsからフォーマット済み文字列を
作り、;;
を前に、改行文字を後につけて現在の出力ポートへと出力します。
典型的なMakefileでのテスト起動では、テストスクリプトの標準出力をログに流すので、 このメッセージもログにのみ記録されることになります。
この手続きは、自動化テストで検査することは出来ないけれどトラブルシューティングに
役に立つかもしれない情報をダンプしておくのに使えます。
例えば、謎のテスト失敗報告が来て、でも手元ではどうしても再現できず、
実行システムに固有のある側面が影響しているのではないかと推測できたとしましょう。
その場合、test-log
でそういった情報をダンプするコードをテストスクリプトに
仕込んでおいて、もう一度報告者のマシンでテストを走らせてもらい、そのログを解析する
ことができるでしょう。
{gauche.test
}
テストスクリプトがいくつかある場合を考えます。通常は、それらのテストスクリプト
をひとつづつ走らせて結果を確かめるのではなく、全部を一気に走らせて
簡単な結果のまとめだけを知りたいと思うでしょう。
test record fileはテスト結果を集積するための補助ファイルです。 その内容は次のような一行のサマリになっています。
Total: 9939 tests, 9939 passed, 0 failed, 0 aborted.
test record fileが既に存在していると、test-start
は
それを読みこんで数字を覚えておきます。そしてtest-end
が
そのスクリプト中のテスト結果の数字を加算して、同じtest record fileに書き戻します。
makefileのcheck
ターゲットを次のように書いておけば、
make check
を実行するたびにテスト結果の一行サマリを
得ることができます。
ただし、test1.scm、test2.scm、test3.scmはいずれも
test-start
呼び出し前に(test-record-file "test.record")
を
評価しているものとします。
check: @rm -f test.record test.log gosh test1.scm >> test.log gosh test2.scm >> test.log gosh test3.scm >> test.log @cat test.record
test-record-file
手続きがうまく動作するためには、それが
test-start
より前に呼ばれなければならないことに注意してください。
この手続きのかわりに、環境変数GAUCHE_TEST_RECORD_FILE
を使って
test record fileを指定することもできます。
テストスクリプトが走る時にこの環境変数が指定されていれば、 その値がtest record fileの名前として使われます。
ただしテストスクリプト中にtest-record-file
の呼び出しがあると
そちらが優先され、この環境変数は無視されます。
{gauche.test
}
テストレコードファイルが(test-record-file
もしくは環境変数
GAUCHE_TEST_RECORD_FILE
によって)設定されていた場合、
それを読み込んで、失敗カウントとアボートカウントがともに0でなければ
終了ステータス1でexitします。テストレコードファイルが設定されていなければ
何もしません。
これは、複数のテストスクリプトを持っていて、どれかが失敗したらmake
に
それを伝えたいけれども、テストスクリプト自体はすべて走らせたい、という場合に便利です。
各テストスクリプトでtest-end
に:exit-on-failure
を
使ってしまうと、make
は失敗したテストスクリプトのところで処理を打ち切って
しまいます。そこで:exit-on-failure
を使うのを避け、
テストレコードファイルを使い、ビルドの最後にこの関数を呼ぶようにします:
check: rm -f $GAUCHE_TEST_RECORD_FILE test.log gosh test1.scm >> test.log gosh test2.scm >> test.log cat $GAUCHE_TEST_RECORD_FILE /dev/null gosh -ugauche.test -Etest-summary-check -Eexit
こうしておくとmake
は失敗があろうともすべてのテストスクリプトを
実行し (gosh
は常に終了ステータス0で終了するので)、
最後の行でテストレコードファイルを参照して、失敗があった場合に
make
にそれを伝えることができます。
多くのテストフレームワークでは、何をテストするかによってtest-assert
や
test-equal
などの様々なテスト手続きを提供しています。
Gaucheではテスト手続きはtest
(およびそのラッパーであるtest*
) だけです。
test
はテストする式(のサンク)、期待される結果、そして省略可能な検査述語を取り、
式の実際の結果と期待される結果を検査述語で比較します。
単純に値を比較する、エラーが投げられることを確認する、など様々なテストは
検査述語によって処理されます。デフォルトの検査述語でも、
以下のような色々なテストに対応できます。
(test* "one plus one equals two" 2 (+ 1 1))
#f
でない値)を返すことを確認する。
(test* "'any' returns non-false value" (test-truthy) (any integer? '(1.2 3/4 5)))
(test* "get random ineteger between 0 and 5" (test-one-of 0 1 2 3 4 5) (random-integer 6))
(test* "expects read error" (test-error <read-error>) (read-from-string "(a .)"))
このようにしておくと、例えば期待される結果とテストサンクのリストを用意して ループするような、テストのパラメタライズが容易にできます。
{gauche.test
}
exprをlambdaでくるんでくれる便利なマクロです。
(test* name expected expr opt ...) ≡ (test name expected (lambda () expr) opt ...)
{gauche.test
}
thunkを呼び、その結果がexpectedに沿っているかを
checkを次のとおり呼び出すことで確認します。
(check expected result-of-thunk)
この手続きは、渡された結果が期待する値と合致する場合に#t
を、
そうでなければ#f
を返さなければなりません。
デフォルトのcheck手続きは下で述べるtest-check
です。
これは、expectedがいくつかの特殊なテストオブジェクトである場合をのぞき、
expectedとresult-of-thunkがequal?
である場合に#t
を返します。すなわち、通常はテスト式の結果が
期待するものとequal?
であればテストは成功である、ということです。
(特別な場合については下の “曖昧な結果をテストする” および
“異常系をテストする” の項を見てください)。
特別な比較手続きのひとつの用法は、非正確な数値を、多少の誤差を許して 比較するような場合です。
(test "test 1" (/ 3.141592653589 4) (lambda () (atan 1)) (lambda (expected result) (< (abs (- expected result)) 1.0e-10)))
nameはログに残すためのテストの名前です。
thunk内で捕捉されないエラーが発生した場合、それは捕捉され、
特別なエラーオブジェクト<test-error>
に置き換えられます。
その結果を、下で説明するtest-error
手続きで作った<test-error>
オブジェクトと比較することにより、エラーが期待されたものであるか、
また適切な例外が上がっているかをテストすることができます。
省略可能引数reportは#f
か、引数を3つ取る手続きです。
checkが偽を返した場合に呼ばれます (ただし、hookが呼ばれる前です)。
最初の引数はname、次の引数はexpeced、最後の引数はthunkが
返した値か、thunkがエラーを投げた場合は<test-error>
オブジェクトです。
デフォルトはtest-report-failure
手続きで、これは単にwrite
を使って
最後の引数(実際の結果、あるいは<test-error>
オブジェクト)を出力するだけです。
別の手続きを与えることにより、テスト失敗時の出力をカスタマイズできます。
最後に、省略可能引数hookは、#f
か4引数の手続きでなければなりません。
それが手続きの場合、test
がテストを終えた後で次の引数で呼び出されます:
第1引数はシンボルpass
かfail
、第2引数はname、
第3引数はexpected、そして第4引数は、thunkの返り値か、
thunkがエラーを投げた場合は<test-error>
オブジェクト。
hookの戻り値は無視されます。
これは、gauche.test
をラップしたライブラリが独自にテスト結果を記録したい
場合に便利です。
註: 0.9.10ではreport引数がありませんでした。report引数を追加するに 当たって、それを最後の省略可能引数ではなく、2番目の省略可能引数として hook引数をずらすことにしました。 hook引数は滅多に使われないだろうという判断です。 互換性のため、report引数に4引数の手続きが渡された場合は 警告を出したうえでそれをhookとして扱うコードが今は入っています。 将来のリリースではこの互換性コードは取り除かれます。
{gauche.test
}
テスト式の結果が期待された値に合致していることをチェックするために
test
とtest*
が使うデフォルトの手続きです。
基本的に、test-check
はexpectedとactualを
equalに渡された手続きで比較するだけです。equalの
デフォルト値はequal?
です。
ただし、以下に述べるとおり、expectedが特殊なテストオブジェクト
だった場合には特別な振る舞いをします。
{gauche.test
}
テスト失敗をレポートする手続きのデフォルトです。これは単に
actual-resultをwrite
で書き出すだけです。
test
やtest*
のreport引数に独自の手続きを渡すことにより、
テスト失敗時の表示をカスタマイズできます。
例えば下のtest-report-failure-diff
を参照してください。
{gauche.test
}
時々、テスト式exprの結果が外部の環境に左右されるため、
ひとつの確定した値を期待値expected
として書いておけない場合があります。
この手続きはそのようなテストを簡単に書けるようにします。
choice … のいずれか を表現する特別なオブジェクトを返します。
デフォルトの検査手続きであるtest-check
は、expected引数に
そのオブジェクトが渡ってきた場合には、テスト結果とchoice …を
ひとつづつ照合し、どれかがマッチすれば真を返します。
例えば次のテストは、proc
が1か2を返せば成功となります。
(test* "proc returns either 1 or 2" (test-one-of 1 2) (proc))
test-check
は各choiceに対してtest-check
を再帰的に
呼びます。すなわち:
(test-check (test-one-of choice ...) result equal) ≡ (or (test-check choice result equal) ...)
従って、各選択肢を比較する手続きをカスタマイズしたい場合は、
それを与えたtest-check
手続きをチェック手続きとして渡してください。
例えば次の例は、各選択肢と結果をstring-ci=?
で比較します:
(test* "Using one-of with case insensitive comparison" (test-one-of "abc" "def") "Abc" (cut test-check <> <> string-ci=?))
{gauche.test
}
choice … のいずれでもない を表現する特別なオブジェクトを返します。
テストは、テスト結果がchoiceのどれにもマッチしなかった時に成功となります。
註: 非正確な数値の結果を比較したい場合は、
approx=?
が使えます (数値の比較参照)。
{gauche.test
}
真の値、つまり#f
以外のあらゆる値を期待するオブジェクトを返します。
テストする式が真の値を返す(が、#t
とは限らない)場合に便利です。
{gauche.test
}
与えられたcondition-typeと適合する<test-error>
オブジェクト
とマッチするような、新たな<test-error>
オブジェクトを作成して返します。
テスト結果をチェックするtest-check
手続きは<test-error>
オブジェクトを
特別に扱います。err-expected
とerr-actual
が
ともに<test-error>
のインスタンスであるとき、
(test-check err-expected err-actual)
は
err-expected
の持つcondition typeがerr-actual
の
それと同じであるか、スーパータイプである場合に#t
を返します。
例えばfoo
の呼び出しが<io-error>
(もしくはそのサブタイプ) の
コンディションを投げるかどうかをテストしたければ、次のように書くことができます。
(test "see if foo raises <io-error>" (test-error <io-error>) (foo))
もう一つの省略可能引数messageは、テスト中に投げられたエラーの
メッセージが期待するパターンを満たしているかどうかをチェックするのに使います。
この引数は文字列、正規表現、#f
のいずれかでなければなりません。
この引数が文字列の場合、test-check
は投げられたエラーのメッセージが
その文字列と完全に一致するかどうかをチェックします。
この引数が正規表現の場合、test-check
は投げられたエラーのメッセージが
その正規表現にマッチするかをチェックします。
デフォルトは#f
で、その場合はメッセージのチェックは行われません。
{gauche.test
}
Deprecated.
condition typeとして<error>
を持つ<test-error>
オブジェクトに束縛されています。この変数は互換性のためにのみ残されています。
新しいコードは上に述べたtest-error
手続きを使ってください。
{gauche.test
}
この変数が真であれば、test
ルーチンはエラーを捕捉した際に
スタックトレースをカレントエラーポートに出力します。
期待しない状況でtest-errorオブジェクトが返された際に、そのエラーが
どこで起こったかを知るのに役立つでしょう。
この変数はgauche.test
モジュールが読み込まれた時点で
環境変数GAUCHE_TEST_REPORT_ERROR
の値により初期化されます。
例えば、テストスクリプト中の予期せぬエラーを調べるのに、
次のようにすることができるでしょう (環境変数がセットされていれば、値は関係ありません)。
env GAUCHE_TEST_REPORT_ERROR=1 gosh mytest.scm
しばしば、既存の仕様を実装していて、テストコードがその仕様に付属していることがあります。
テストがR7RSで書かれていればそれ自体をGaucheで実行することはできますが、
gauche.test
で管理されるより大きなテストスイートの一部として
与えられたテストを実行したい場合もあるでしょう。
Gaucheではテスト用SRFIであるsrfi.64
やsrfi.78
がgauche.test
と連携するようになっているので、テスト結果がまとめて報告されます。
ただ、テストがR7RS形式で書かれている場合、それをGaucheのテストスイートに
単純にinclude
するだけではうまくいかないことがあります。
Gaucheにもともとあったimport
とR7RSのimport
は異なっているので、
Gaucheは実行時に、
プログラム中で最初に出会うimport
でどちらかを切り替える黒魔術を使っています
(3つのimport形式参照)。
Gaucheプログラム中にR7RSプログラムをインクルードした場合、R7RSプログラム中の
import
がGaucheのimport
と解釈されてしまうのでうまくありません。
かわりに、下のマクロtest-include-r7
が使えます。
註: 外部テストがChibi Scheme向けに書かれている場合、
chibi-test
が使えます(compat.chibi-test
- Chibi schemeテストの実行参照)。
{gauche.test
}
include
フォーム (インクルード参照) と同じように、
pathで指定されるファイルの内容をこのマクロの位置に挿入します。
pathが相対パスの場合は、インクルードしているファイルからの相対になります。
ファイル中のコードは、import
がR7RSのimport
に束縛された
環境で挿入されます。したがってR7RSで書かれたテストスクリプトがそのまま実行できます。
推奨される使い方は、Gaucheのテストスクリプト中に別のモジュールを作ってその中で インクルードする方法です。
(use gauche.test) (test-start ...) : (test-section "xxx-tests") (define-module xxx-tests (use gauche.test) (test-include-r7 "xxx-tests"))
しばしば、与えられたテストスクリプトが、Gaucheにない名前でライブラリを参照
していることがあります (例えばtests/include/srfi-222-tests.scm
は(compounds)
というライブラリをインポートしていますが、
Gaucheではそのライブラリはsrfi.222
という名前で提供されています)
その場合、Gaucheに無いモジュールをexclude-clauseに列挙することで、
import
がそのモジュールを無視するようにできます:
(define-module srfi-222-tests (use gauche.test) (use srfi.222) (test-include-r7 "include/srfi-222-tests" (exclude (compounds))))
exclude-clauseは次の形式を取ります:
<exclude-clause> : (exclude r7rs-library-name ...)
上記test
の項で説明したように、test
手続きやtest*
マクロの
report引数に手続きを渡すことで、失敗の報告をカスタマイズできます。
便利なカスタマイズのひとつは、複数行に渡るテキストの差分を示すことです。
これはとても便利なので、それ用の手続きを用意しました。
これはちょっとわざとらしいテストです。
test-report-failure-diff
をreport引数に渡しています
(それと、check引数にtest-check-diff
を渡しています。後で説明します。)
期待される結果は行のリストで、実際の結果は単一の文字列になっています。
test-report-failure-diff
とtest-check-diff
手続きは、
expectedとactualに渡されるものを単一の文字列へと正規化するので、
渡しやすいような形式で引数を渡すことができます。
(test* "Beatrice"
;; expected
'("What fire is in mine ears? Can this be true?"
"Stand I condemned for pride and scorn so much?"
"Contempt, farewell, and maiden pride, adieu!"
"No glory lives behind the back of such.")
;; actual
"What fire is in mine ears? Can this be true?\n\
Stand I condemn'd for pride and scorn so much?\n\
Contempt, farewell! and maiden pride, adieu!\n\
No glory lives behind the back of such.\n"
test-check-diff ; check
test-report-failure-diff) ; report
⇒ Reports:
ERROR: GOT diffs:
--- expected
+++ actual
@@ -1,4 +1,4 @@
What fire is in mine ears? Can this be true?
-Stand I condemned for pride and scorn so much?
-Contempt, farewell, and maiden pride, adieu!
+Stand I condemn'd for pride and scorn so much?
+Contempt, farewell! and maiden pride, adieu!
No glory lives behind the back of such.
このとおり、結果がunified diffフォーマットで報告されるので、どこが違っているのか
見つけやすくなります
(unified diffフォーマットについてはtext.diff
- テキストストリームの相違点を計算する参照)。
{gauche.test
}
test
手続き/test*
マクロのcheck引数に渡せる
チェック手続きです。
まず、expectedとactualを次の規則によって正規化します。
\n
を糊としてひとつの文字列へとjoinします
(suffix
シンタックスを使います。つまり、最後の行の末尾にも\n
は付きます)。
(content-of <string>)
という形であれば、
<string>
をファイル名と解釈し、そのファイルを読み込んだ文字列を使います。
ファイル名が相対パスの場合、現在ロードしているファイルからの相対と解釈されます。
ファイルが無ければ空文字列になります。
正規化後、二つの引数がequal手続きによって比較されます。デフォルトはequal?
です。
{gauche.test
}
test
手続き/test*
マクロのreport引数に渡せる
チェック手続きです。
まずexpectedとactual引数がtest-check-diff
と同様に
正規化されます。つまり、文字列のリストか(content-of <filename>)
ならば
単一の文字列に変換されます。
それから、両者の差異をunified diff形式で表示します
(diff-report/unified
が使われます。
text.diff
- テキストストリームの相違点を計算する参照)。
expectedとactualの少なくとも一方が文字列に変換されなかった場合は、
標準のtest-report-failure
と同じ表示になります。
註: この手続きは、テストが失敗した時だけでなく、test-end
がテスト結果の
まとめを表示する時にも呼ばれます。
従って、(content-of <filename>)
の形式を使う場合は、
test-end
が戻るまで<filename>
が存在するようにしてください。
例えばテスト内で一時ファイルを作って結果をそこに出し、そのテスト後にクリアする、
という場合はこの形式は使い辛いでしょう。
一般的に、(content-of <filename>)
形式は、expectedに
あらかじめ用意してあるファイルを指定するのに使うのが良いでしょう。
{gauche.test
}
test*
マクロでtest-check-diff
とtest-report-failure-diff
を
checkとreport引数に指定したもので、簡便のために用意されています。
(test*/diff name expected expr) ≡ (test* name expected expr test-check-diff test-report-failure-diff)
Schemeは動的型付けで、これはREPLでインクリメンタルあるいは実験的な開発を するには便利なのですが、コードが実際に走るまでエラーに気づかないということになりがちです。 しばらく走らせた後で変数名のタイポで止まってしまうと腹立ちますよね。
Gaucheでは、こういった種類のエラーをテスト時に検査する方法を用意しています。 これは完全に静的な検査ではありません(対象のモジュールやスクリプトをロードするので、 トップレベル式は実行されてしまいます)し、網羅的でもありません (複数のモジュールを見たり、実行時に追加される情報に依存するものは検査できません)。 それでも、変数名の間違いや引数の個数の誤りなどよくあるミスはこの検査で大抵見つけることが できます。
test-module
とtest-script
手続きはそれぞれ、
指定されたモジュールもしくはスクリプトをロードし (その過程でSchemeコードは
VM命令列へとコンパイルされます)、次にコンパイルされたVMコードを走査して
以下のテストを行います。
今のところ検査はヒューリスティックで、エラーを見逃すこともあれば、 エラーでないものをエラーと報告してしまう可能性もあります。後者については、 偽陽性となるシンボルを列挙して検査から外すようにできます。
{gauche.test
}
モジュールをロードし、準静的な一貫性チェックを行います。
Moduleはモジュール名のシンボルかモジュールでなければなりません。
しばしば、プラットフォームやコンパイルオプションによって
グローバル変数が定義されるかどうかが異なる場合があります。
コード中では実行時にその変数の存在を確認してから使うように
コーディングしてあったとしても、test-module
は
そのようなロジックを追わないため、未定義変数の参照を報告して
しまいます。そのような場合は、チェックから外す変数名のリストを
allow-undefinedキーワード引数に渡して下さい。
引数の個数のチェックも、偽陽性のエラーをあげる可能性があります。
モジュールがロードされた後のグローバルな関数の変更を当てにしている場合などです
(例えば、コード中であるジェネリックファンクションに渡されている引数の個数が、
モジュールのロード時点では不正なものだったとしても、そのコードが実行される
までに該当引数のメソッドが追加されれば、正しいコードとなるわけです)。
自分のコードは確かに正しく、チェックが誤りであるような場合は、
該当関数の名前のリストをbypass-arity-check
キーワード引数に
渡してください。
{gauche.test
}
filenameで指定されるスクリプトを新しい無名モジュールにロードし、
準静的な一貫性チェックを行います。
filenameはスクリプトファイル名を指定する文字列でなければなりません。
キーワード引数の意味はtest-module
と同じです。
filename中のトップレベルフォームは評価されるので、
トップレベルフォームのアクションに依存したスクリプトは望ましくない副作用を生じるでしょう。
この検査は、スクリプトがSRFI-22形式、
つまりアクションをmain
手続きから呼ぶようになっているとうまくいきます。
R7RSスクリプトはトップレベルフォームのアクションに頼らざるを得ないので
この手続きではうまく検査できません。
スクリプトがuser
モジュールにロードされることに依存して書かれている場合も、
この手続きではうまくいきません。
もしスクリプトに副作用があるトップレベルフォームが書かれていて、それを
変更することができないなら、compile-only
キーワード引数に
真の値を渡してみてください。すると、test-script
は
スクリプトのトップレベルフォームをコンパイルだけしてから静的検査を行います。
(デフォルトのload
はコンパイルだけではなく実行も行います)。