Tcltestでテストする

最近テスト・ファースト(Test First)やテスト駆動型開発(TDD: Test Driven Development) という言葉をよく聞くようになりました。 私は開発方法論の専門家でないのでうそっぴで覚えていますが、 ごくごく簡単には、 「本来のソースコードよりも、その動作を検証するためのコードを先に書け」 という考え方です。 ナニが良いのかというと、 先に検証用コードを書くと、本来のコードを書くときに、 それが使われる状況や、どんな条件分岐や例外処理を書かなければいけないかを、 より明確に意識しながらプログラミングできるようになる、ということです。 また、最近ではこの検証用コードからテスト結果報告書を自動生成するツールなども現れていて、 「無駄なドキュメントは極力書かない」 というXPやアジャイルなど新しい開発スタイル (無駄な、がナニを指すのかはしばしば議論になりますが) に適合するとしてほめられている考え方です。

そのような時代を反映して、例えばJavaにはJUnit、C++にはCppUnitなどの、 単体テスト・ツール・パッケージがありますが、 TclにもTcltestなるパッケージが同梱されています。 使い方はJUnitなどと似ていて、ある処理に対するテスト・ケースを複数定義しておき、 まとめて走らせて、処理の結果が期待した値と異なる場合にはエラーを出力する、 というものです。

さわりだけとっついてみたので、簡単な例を挙げます。

package require dpu
package require tcltest
namespace import ::tcltest::*

namespace eval replacetest {

  test replacetest-1 "test of ::dpu::replace 1" -body {
    ::dpu::replace "abcdefghi" def jkl
  } -result "abcjklghi"

  test replacetest-2 "test of ::dpu::replace 2" -body {
    ::dpu::replace "abcdefghidef" def jkl
  } -result "abcjklghijkl"

  test replacetest-3 "test of ::dpu::replace 3" -body {
    ::dpu::replace "今日は雨ですが、明日は晴れでしょう。" 明日 明後日
  } -result "今日は雨ですが、明後日は晴れでしょう。"

}

これはdpuというパッケージに入っている、replaceというコマンドを試しています。 (勿論、それはTcl標準のコマンドではないですよ。 私がこちらで作ったもので、 「replace a b c」とすると、文字列aに含まれるbをcに変換して返す、 というだけの単純な処理です)
Tcltestするには、Tcltestパッケージをロードします。 その全てのコマンドは::tcltest名前空間に居るので、例のようにインポートするとokです。 各「テスト」を行う::tcltest::testコマンドは、次のような形をしています。

test name description
?-constraints keywordList|expression?
?-setup setupScript?
?-body testScript?
?-cleanup cleanupScript?
?-result expectedAnswer?
?-output expectedOutput?
?-errorOutput expectedError?
?-returnCodes codeList?
?-match mode?

よく使うのは-setup、-body、-cleanup、-resultだと思います。 JUnitと同様、-setupにはテスト前の初期化コード、 -bodyにはテスト処理本体、-cleanupにはテスト後の後始末(変数のunsetなど)を書きます。 -resultには期待する値を書きます。 -bodyの処理内容と-resultの値が異なれば、テストはエラーになる、ということです。

やねうらの top
(first uploaded 2006/01/03 last updated 2006/01/03, MISUMI URANO)