* UnitTest は
* UnitTest は [#qc60aa62]
ある機能を提供する関数を作成する場合に,
  (1) まず,その挙動を Test する関数を用意し
  (2) この Test をパスすることを目的として当該の関数を書いていく
という方法論です.この Test -> Release -> Test -> Release のサイクルを繰り返すことで,(部分的に)正常な動作が常に保証された関数を逐次完成させていきます.

一般的にはオブジェクト指向言語においてクラスの振舞いを Test する文脈で導入されますが,R の場合は日常的にはクラスの作成よりも関数の作成の方が多いと思われるので,以上のように記述しました.

----
CRAN に登録されている[[RUnit:http://cran.md.tsukuba.ac.jp/src/contrib/Descriptions/RUnit.html]] パッケージを利用して,R でも UnitTest を実践することができます.
[[RUnit を使う]] に使用例が記されています.

----
* alternative approach
* alternative approach [#d4119192]
その他には,[[プログラムの正しさのチェック]] に diff を用いたチェック例があります.

[[プログラムの正しさのチェック]] (7) 注釈より
  * 膨大な出力ファイルでもかまわない
  * プログラムの改訂があれば,必要に応じて answer ファイルも改訂する
  * プログラムの改訂があったとき,いつでもこのチェックをする必要はない

対照しますと,UnitTest では
  * 膨大なチェック個数でもかまわない
  * 関数を修正しても,(正常に動作している)テスト関数は修正しない
  * 関数の修正があったときには,必ずテストを実行する
という違いがあります.

----
* 疑問
* 疑問 [#cffda34c]
- テスト関数は正しいのか
-- 保証できません.
- 因子分析の出力をテストするには,大変な思いをしなくてはならないのではないか
-- その通りです.

----
R において,UnitTest 的な Test Driven な関数作成を行えると,幾つかの関数を連係させたアプリケーションを作成する際に有用な Tips になると思います.

// とはいえ,関数型言語だといまいちそぐわないようにも感じているのですが.[[SchemeUnit:http://schematics.sourceforge.net/schemeunit.html]] というのが R とは近いでしょうか.
// とはいえ,関数型言語だといまひとつそぐわないようにも感じているのですが.[[SchemeUnit:http://schematics.sourceforge.net/schemeunit.html]] というのが R とは近いでしょうか.


----

* UnitTest のコンセプトを説明するためのサンプル
* UnitTest のコンセプトを説明するためのサンプル [#o86e9ff4]

- 目的: 二つの数の和を返す myfunc(a, b) を作成する
- 確認項目 1: 1+1 = 2 であれば正常な動作である
- 確認項目 2: 必要なだけ確認項目を用意する
- ...

** (1) ''test.myfunc()'' を用意する.
** (1) ''test.myfunc()'' を用意する. [#m95aa5f6]

  test.myfunc <- function()
  {
     if( myfunc( 1, 1 ) == 2 ) {
        return( TRUE )
     else
        return( FALSE )
     }
  }

** (2) Test を行う
** (2) Test を行う [#t91c23b2]
失敗する.

今回の場合は,そもそもテスト関数にエラーがある.

「テスト自体が間違っている」という可能性は常に存在する.

** (3) test.myfunc() を修正し,再度 Test する
** (3) test.myfunc() を修正し,再度 Test する [#s9454606]
再び,失敗する.

myfunc() が定義されていない.

しかし,test.myfunc() は正常に実行されることが確認された.

** (4) ''myfunc()'' を書く
** (4) ''myfunc()'' を書く [#ued28735]

  myfunc <- function(a, b)
  {
     return(a - b)
  }

** (5) テストを行う
** (5) テストを行う [#vbd40929]
三度目の失敗.myfunc() で差をとっているため.

** (6) myfunc() を修正し,Test する
** (6) myfunc() を修正し,Test する [#j586944e]
成功.

** (7) myfunc() の拡張が決まった
** (7) myfunc() の拡張が決まった [#wd66e162]
- 目的(改): 引数がベクトルであってもよいことにする
- 追加する確認項目:ベクトル引数の足し算が正常に行われるか?

** (8) test.myfunc() にチェック項目を追加し,テストする
** (8) test.myfunc() にチェック項目を追加し,テストする [#e15d3903]
あ,うまくいった.R だからね. 

----

* コメント
* コメント [#td4d4b06]
- test.myfunc 中に関数 myfunc の期待される挙動の検査項目をリストアップしておき、それにすべてパスしたら TRUE を返すように設計するという趣旨ですね。 --  SIZE(10){2003-07-26 (土) 23:39:04}
-そうです.常に Test をクリアするように記述することで信頼性を高め,コンスタントに改良を加えられるようにする,という考え方と理解しています. --  SIZE(10){2003-07-26 (土) 23:47:46}
-このページを書いたときの例は,RUnit の登場以前に書かれたものです.現在,RUnit においてこのテストを行うには checkEqualsNumeric() を使用します. 
  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 
となり,つまり定められた仕様に反する値を返していることを示しています.--  &new{2004-07-06 (火) 19:00:23};

#comment

* リンク
* リンク [#l9ff90aa]
//- [[UnitTest:http://c2.com/cgi/wiki?UnitTest]]
- [[SchemeUnit:http://schematics.sourceforge.net/schemeunit.html]]

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS