書き方というかテスト作成の考え方はJUnitとかCppUnitと大体同じで、複数のテストを書いたテストユニットをファイルごとに作成して、それをスイートにまとめて実行するという感じです。まずはテストユニットを書きます。雛型はこんな感じです。

 package require tcltest
 eval tcltest::configure $argv
 
 package require hoge
 
 namespace eval ::hoge::test {
    test TestName TestDetail {
    expr 1+1
  } 2
  cleanupTests
 }
 namespace delete ::hoge::test

この例ではhogeというパッケージを(使ってないけど)テストしているつもりです。package requireだけでなくて、loadやsourceなどでテスト対象を読み込んでもいいでしょう。
test TestName TestDetail ...とあるのがテストコマンドで、ASSERT文のようなもんです。TestName TestDetailはそれぞれわかりやすい名前を書いておきます。失敗した個所の行番号とかは出ないでTestNameとTestDetailが出力されるので、TestNameにHogeTest1-1のように連番を書き、TestDetailにその説明を書くことが多いようです。同じ名前がかぶっても問題ないので、めんどくさいときはTestNameをみんな同じにしたりしてます。

このテストコマンドの書き方は省略した書き方で、正規の書き方を使ってテストコマンドごとにsetup、cleanupを使って変数の準備と後始末をしたり、プラットフォームごとに実行に制約を付けたりなどすることもできます。

テストファイル中で全てのテストの最後にtcltest::cleanupTestsを呼んでテスト結果を収集したりなどの後始末をします。ちなみにnamespaceを使っているのは、他のテストと同じインタプリタ内で実行されたときに互いに干渉しあわないようにするための工夫です。singleprocオプションでファイルごとに子インタプリタを作る方法しか使わないというならnamespaceでまとめなくてもよいと思いますが。。。

で、これをhoge.testとか拡張子を.testにして適当なディレクトリにおきます。testという名前のディレクトリを作ってそこに置くとよいと思います。あと、ファイルごとにtcltestをrequireしてるのは、この1ファイル単体だけでもテストを実行できるようにするためです。例えばtclsh hoge.testのようにすれば、1ファイル単体でテストできます。が、まあ通常はまとめて実行するスイートを作ります。スイートはall.tclという名前で、次のような簡単なスクリプトです。

 package require Tcl 8.4
 package require tcltest
 
 tcltest::configure -debug 0
 tcltest::configure -singleproc no
 tcltest::configure -testdir [file dir [info script]]
 
 eval tcltest::configure $argv
 tcltest::runAllTests

これはrunAllTestsコマンドで、all.tclと同じディレクトリにある.testの拡張子のファイルをsourceしてテストを実行し、その結果を表示します。-singleprocは、yesの時は全ての.testファイルが同じインタプリタのスレッド(スレッドじゃないけど)で実行されます。noの時は、.testファイルごとに子インタプリタを作成してそこでテストを実行します。デフォルトはnoです。単体テストとしてならnoで使うのが良いと思います。-debugは0~3の数字でテスト実行中の詳細を表示するレベルを指定します。

で、tclsh all.tclのように実行すると、テストを実行して、その結果を表示します。
テストコマンドの多くは簡略化した書き方で書くと思います。たとえばつぎのように。

 package require tcltest
 namespace import ::tcltest::*
 test Test1-0 {テストのテスト} {
  expr 3*2
 } 6

基本的には、こうです。では小数値が含まれてたりするときはどうしましょう。
まあ、こうかな・・?
 test Test2-0 {浮動小数値のテスト1} {
  format %1.2f [expr 2.0 * asin(1)]
 } 3.14

正規表現でマッチングさせることもできます(汗)
 test Test2-1 {浮動少数値のテスト2} -body {
  expr 2.0 * asin(1)
 } -result {^3\.14\d*$} -match regexp

テストコマンドは、最後のリターンだけ比較するので、次のように複数の文も実行できます。ただこの例では変数aを後始末しないとよろしくありません。
 test Test3-0 {変数の使用のテスト0} {
  set a 123
  expr $a + 123
 } 246

まあ、このように・・・。
 test Test3-1 {変数の使用のテスト1} {
  set a 123
  expr $a + 123
 } 246
 unset a

ただしく書くならsetup、cleanupを使ってこのように書くのが望ましいでしょう。(見にくいからあまり好きじゃないけど)
 test Test3-2 {変数の使用のテスト2} -body {
  expr $a + 123
 } -setup {
  set a 123
 } -cleanup {
  unset a
 } -result 246

複数のテストコマンドで同じ変数を使うときは、いちいちsetup、cleanupを書くのは馬鹿らしいので、
 variable SETUP {set a 123}
 variable CLEANUP {unset a}

のようなものを定義しておいて、

 test Test3-3 {変数の使用のテスト3} -body {
  expr $a + 123
 } - result 246 -setup $SETUP -cleanup $CLEANUP
と、まあこのように。

基本的に最後にリターンされた値を比較するわけですが、複数の値を比較するにはリストを使います。これは結構便利に使える工夫です。
 test Test4-0 {複数の値をアサートするテスト0} {
  set a 123
  set b 456
  list $a $b
 } {123 456}

こんな風にも書けます。
 test Test4-1 {複数の値をアサートするテスト1} {
  list \
  [expr 120 + 3] \
  [expr 450 + 6]
 } {123 456}


***参考リンク
http://www.freesoftnet.co.jp/tclkits/doc/TclCmdRef/TclCmd/tcltest_jp.htm

----
[[CategoryTclTk]]



HTML convert time: 0.003 sec.