[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.22 gauche.test - 単体テスト

Module: 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)

このテストスクリプトは、バッチ処理でもインタラクティブセッションからでも 実行できます。インタラクティブセッションの場合はこのテストスクリプトを ただロードすれば、各テストの結果とサマリーが報告されます。 バッチテストの場合は、標準出力を別のファイルにリダイレクトしておくと良いでしょう。 標準出力が端末でない場合、テスト手続きは詳しい結果をstdoutに出力し、簡単な メッセージを標準エラー出力に書き出します。

モジュールやプログラムを書いたら、Makefileに"check"ターゲットを作ることを お薦めします。ルールはこんな感じになるでしょう:

 
check :
        gosh my-feature-test.scm > test.log

テストファイルの構造

Function: test-start module-name

テストの状態を初期化して、ヘッダをログに書き出します。テストを呼ぶ前に呼んで下さい。 module-nameはログのために使われる文字列です。

Function: test-section section-name

一群のテストの開始をマークします。単にログに使われるだけです。

Function: test-end

失敗したテストのリストを報告し、その総数を返します。

Function: test-record-file file

テストスクリプトがいくつかある場合を考えます。通常は、それらのテストスクリプト をひとつづつ走らせて結果を確かめるのではなく、全部を一気に走らせて 簡単な結果のまとめだけを知りたいと思うでしょう。

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
        @echo test.record

test-record-file手続きがうまく動作するためには、それが test-startより前に呼ばれなければならないことに注意してください。

この手続きのかわりに、環境変数GAUCHE_TEST_RECORD_FILEを使って test record fileを指定することもできます。

Environment Variable: GAUCHE_TEST_RECORD_FILE

テストスクリプトが走る時にこの環境変数が指定されていれば、 その値がtest record fileの名前として使われます。

ただしテストスクリプト中にtest-record-fileの呼び出しがあると そちらが優先され、この環境変数は無視されます。

個々のテスト

Macro: test* name expected expr &optional compare

exprをlambdaでくるんでくれる便利なマクロです。

 
(test* name expected expr)
  ≡ (test name expected (lambda () expr))
Function: test name expected thunk &optional check

thunkを呼び、その結果がexpectedに沿っているかを checkを次のとおり呼び出すことで確認します。

 
(check expected result-of-thunk)

この手続きは、渡された結果が期待する値と合致する場合に#tを、 そうでなければ#fを返さなければなりません。 デフォルトのcheck手続きは下で述べるtest-errorです。 これは、expectedが特殊な<test-error>オブジェクトである 場合を除いては、expectedresult-of-thunkequal? である場合に#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> オブジェクトと比較することにより、エラーが期待されたものであるか、 また適切な例外が上がっているかをテストすることができます。

異常系をテストする

Function: test-error &optional (condition-type <error>)

与えられたcondition-typeと適合する<test-error>オブジェクト とマッチするような、新たな<test-error>オブジェクトを作成して返します。

テスト結果をチェックするtest-check手続きは<test-error>オブジェクトを 特別に扱います。err-expectederr-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))
Variable: *test-error*

(非推奨) condition typeとして<error>を持つ<test-error> オブジェクトに束縛されています。この変数は互換性のためにのみ残されています。 新しいコードは上に述べたtest-error手続きを使ってください。

Variable: *test-report-error*

この変数が真であれば、testルーチンはエラーを捕捉した際に スタックトレースをカレントエラーポートに出力します。 期待しない状況でtest-errorオブジェクトが返された際に、そのエラーが どこで起こったかを知るのに役立つでしょう。

この変数はgauche.testモジュールが読み込まれた時点で 環境変数GAUCHE_TEST_REPORT_ERRORの値により初期化されます。 例えば、テストスクリプト中の予期せぬエラーを調べるのに、 次のようにすることができるでしょう (環境変数がセットされていれば、値は関係ありません)。

 
env GAUCHE_TEST_REPORT_ERROR=1 gosh mytest.scm

モジュールのテスト

Function: test-module module &keyword allow-undefined

Moduleはモジュール名のシンボルかモジュールでなければなりません。 この手続きはモジュールmoduleに関していくつかの経験的な一貫性チェックを 行います:(1) autoloadに設定されたシンボルがちゃんとロードできるか、 (2) exportにリストされたシンボルがモジュール内で定義されているか、 (3) 関数中で参照されているグローバル変数が全て定義されたものであるか。 この手続きは完璧ではないものの、 ケアレスミスによる名前の綴り間違いを発見することができます。

しばしば、プラットフォームやコンパイルオプションによって グローバル変数が定義されるかどうかが異なる場合があります。 コード中では実行時にその変数の存在を確認してから使うように コーディングしてあったとしても、test-moduleは そのようなロジックを追わないため、未定義変数の参照を報告して しまいます。そのような場合は、チェックから外す変数名のリストを allow-undefinedキーワード引数に渡して下さい。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.