ある機能を提供する関数を作成する場合に,
(1) まず,その挙動を Test する関数を用意し (2) この Test をパスすることを目的として当該の関数を書いていく
という方法論です.この Test -> Release -> Test -> Release のサイクルを繰り返すことで,(部分的に)正常な動作が常に保証された関数を逐次完成させていきます.
一般的にはオブジェクト指向言語においてクラスの振舞いを Test する文脈で導入されますが,R の場合は日常的にはクラスの作成よりも関数の作成の方が多いと思われるので,以上のように記述しました.
CRAN に登録されているRUnit パッケージを利用して,R でも UnitTest を実践することができます. RUnit を使う に使用例が記されています.
その他には,プログラムの正しさのチェック に diff を用いたチェック例があります.
プログラムの正しさのチェック (7) 注釈より
* 膨大な出力ファイルでもかまわない * プログラムの改訂があれば,必要に応じて answer ファイルも改訂する * プログラムの改訂があったとき,いつでもこのチェックをする必要はない
対照しますと,UnitTest では
* 膨大なチェック個数でもかまわない * 関数を修正しても,(正常に動作している)テスト関数は修正しない * 関数の修正があったときには,必ずテストを実行する
という違いがあります.
R において,UnitTest 的な Test Driven な関数作成を行えると,幾つかの関数を連係させたアプリケーションを作成する際に有用な Tips になると思います.
test.myfunc <- function() { if( myfunc( 1, 1 ) == 2 ) { return( TRUE ) else return( FALSE ) } }
失敗する.
今回の場合は,そもそもテスト関数にエラーがある.
「テスト自体が間違っている」という可能性は常に存在する.
再び,失敗する.
myfunc() が定義されていない.
しかし,test.myfunc() は正常に実行されることが確認された.
myfunc <- function(a, b) { return(a - b) }
三度目の失敗.myfunc() で差をとっているため.
成功.
あ,うまくいった.R だからね.
test.myfunc <- function() { checkEqualsNumeric(myfunc(1, 1), 2) # checkEqualsNumeric() を使用 } myfunc <- function(a, b) { return(a - b) # 和ではなくて差を取ってしまった }実行結果は
> runTestFile("tests.R") Error in checkEqualsNumeric(myfunc(1, 1), 2) : Mean absolute difference: 2 Timing stopped at: 0 0 0 0 0 Number of test functions: 1 Number of errors: 0 Number of failures: 1となり,つまり定められた仕様に反する値を返していることを示しています.-- 2004-07-06 (火) 19:00:23