BVUnit2を利用したユニットテストのチュートリアルです.
以下のようなプログラムを作成しようとしていると,仮定します.このプログラムは,標準Exeから利用されるファイルで,クラスファイルと標準モジュールファイルで提供される物とします.
ファイル名 | モジュール名 | 説明 |
---|---|---|
Vector.cls | Vector | ベクトルクラス |
VectorUtil.bas | VectorUtil | ベクトル演算を定義したモジュール |
名前 | 型宣言 | エラー | 説明 |
---|---|---|---|
Dimention | : () -> Long = Property[r] | - | ベクトルの次元 |
Value | : Long -> Double = Property[r/w] | indexがおかしいと,エラー | ベクトルの値 |
名前 | 型宣言 | エラー | 説明 |
---|---|---|---|
Add | : Vector * Vector -> Vector = Function | ベクトルの次元が異なるとエラー | ベクトル同士の加算 |
CreateVector | : Long -> Vector = Function | 次元を指定するLongが0以下でエラー | ベクトルを生成 |
Mul | : Vector * Double -> Vector = Function | - | ベクトルにスカラーを乗算 |
Norm | : Vector -> Double = Function | - | ベクトルのノルム |
Normalize | : Vector -> Vector = Function | Norm=0でエラー | 正規化したベクトルを返す |
最初に,テスト用プロジェクトを作成します.ここでは,TestVectorとします.このステップは,テストプロジェクトにテストに必要なファイルを登録するところまでです.
標準Exeプロジェクトを新規作成します.
Form1がデフォルトで登録されていますが,不要なので削除します.また,Module1,Vector,VectorUtil,TEST_Vector,TEST_VectorUtilを追加します.Module1とVectorUtilは標準モジュールで,他は全てクラスモジュールです.
プロジェクトの参照設定で,「BVUnit2」を登録します.
さらに,プロジェクトのプロパティで,スタートアップを「Sub Main」に変更します.また,プロジェクト名もここでTestVectorに変更しておきましょう.(Form1を開放した時点で,スタートアップはSub Mainになっていますね・・・)
ここまでで,一度プロジェクトとファイルを保存しましょう.ここでは,「VectorLib\tests」にVectorTest.vbp,Module1.bas,TEST_Vector.cls,TEST_VectorUtil.clsを,「VectorLib\Lib」にVector.cls,VectorUtil.basを保存することにします.
もちろん,ファイル名やファイルの配置は自由でかまいません.
Step2ではテストコードを記述する直前までの,おまじないに関して説明します.
とりあえず,Module1にSub Mainを用意しておきましょう.この時点では,コードは記述する必要はありません.
[Module1] Sub Main End Sub
テストクラス−TEST_Vector,TEST_VectorUtil−には,BVUnit2.ITestをimplementsする必要があります.以下のように記述します.
[TEST_Vector,TEST_VectorUtil] Implements BVUnit2.ITest Private Sub ITest_Setup(ByVal ast_ As BVUnit2.IAssert) End Sub Private Sub ITest_Teardown() End Sub
ITest_Setupは,テストを実行する前にコールされます.ITest_Teardownはテストが終了したあとにコールされます.ITest_Setupはテスト固有の初期化処理を実行するために用意してありますが,もう一つ重要な役割があります.BVUnit2.IAssertのast_を,テスト内に捕まえておくことです.ここでは,次のようにプログラムします.
[TEST_Vector, TEST_VectorUtil] Implements BVUnit2.ITest Private ast As BVUnit2.IAssert Private Sub ITest_Setup(ByVal ast_ As BVUnit2.IAssert) Set ast = ast_ End Sub Private Sub ITest_Teardown() End Sub
astとするかm_astとするか,あるいは他の名前を使うかは,もちろんプログラマの自由ですが,テストであることを考えると,astと簡潔にすませるのが最適だと思います.メンバ変数をastとできるよう,Setupの仮引数にはast_と命名してあります.
テストでは,astを通じて,Assertionを行います.Assertionが真か偽かをBVUnitは判定し,テストが成功したか失敗したかを判断します.
このテストを実行できるよう登録しなくてはなりません.Sub Mainに次のように記述します.
Sub Main() BVUnit2.TestInGUI True, BVUnit2.CreateSuite("Test Vector suite", New TEST_Vector), _ BVUnit2.CreateSuite("Test VectorUtil suite", New TEST_VectorUtil) End Sub
BVUnit2.TestInGUIは,引数として受け取ったテストスイートを実行対象としてテストを行う画面を表示します.一つ目の引数Trueは,ユーザーの指示を待って実行するかを決定するパラメータです.Falseを渡すと,画面表示と同時にすべてのテストスイートをテストし,結果を表示します.
BVUnit2.CreateSuiteはテストスイートオブジェクトを作成する関数です.一つ目の引数がテストスイートの名前になります.テストスイートには,複数のテストを登録できるので,VectorLibに含まれる二つのモジュールをスイートとして含むように,CreateSuite("Test VectorLib suite", New TEST_Vector, New TEST_VectorUtil)としてもかまいません.ここでは,上に示したコード例のようにプログラムしたとして進めます.
ここまでプログラムした時点で,実行してみると,次のような画面が表示されます.
まだテストを書いていないので,実行してもなにも表示されない・・・わけではないですね.
## Tests Ran: 0 | Passed: 0 | Failed: 0 | Error: 0 | Skiped: 0
と,0個のテストが実行されたことが表示されます.これからテストを書かなくてはいけません.
とりあえず,VectorとVectorUtilのインタフェースを記述します.次のようにしました.
[Vector] Public Property Get Dimention() As Long End Property Public Property Get Value(ByVal index As Long) As Double End Property Public Property Let Value(ByVal index As Long, ByVal new_value As Double) End Property
[VectorUtil] Public Function CreateVector(ByVal dim_ As Long) As Vector End Function Public Function Add(ByVal vec1 As Vector, ByVal vec2 As Vector) As Vector End Function Public Function Mul(ByVal vec1 As Vector, ByVal f As Double) As Vector End Function Public Function Norm(ByVal vec1 As Vector) As Double End Function Public Function Normalize(ByVal vec1 As Vector) As Vector End Function
テストファーストにしたがえば,テストを先に記述するべきなのですが,VBだとインタフェースを先に書いた方が便利なのでそうします.インタフェースがアレですと,コンパイルも通らないことですし.
それでは実際にテストコードを記述してみましょう.IAssertのテスト用APIを説明した後,実際に記述した後のテストコード例を示します.
BVUnit2では,ITestを実装したクラスのPublicなサブルーチンのうち,"Test"で名前が始まるものをテスト関数として認識します.例えば,次のようなサブルーチンはテスト関数として認識されます.
テスト関数の型はML風に書くところの「unit -> unit」となっています.引数ゼロ,返り値なしです.
BVUnit2では,あるサブルーチンがエラーを発生することをテストすることができます.つまり,ある一連のプログラム片が特定の番号のエラーをRaiseすることをテストできます.ITestを実装したクラスのPublicなサブルーチンうち,"Err"で名前が始まるものが,エラーチェック関数として認識されます.名前の例は次にしめすリストの通り.
ByRef渡しのLongの値をパラメータとして利用します.実際のテストコードでは,ByRef e As Longとか書くのはだるいので,ByRefを省略し,さらにLongの値を代入できるVariant型としても良いので,eだけで問題ありません.
eには,発生して欲しいエラーの番号をプログラムがエラーを発生するまでに設定しておきます.
Public Sub ErrTest(e) e = 9 'Err.Raise 10 Err.Raise 9 End Sub
などとします.BVUnit2は,ErrTestをコールした際にエラーが発生すると(あるいはエラーが発生しなくても)eに渡した値とErr.Numberを比較し,等しかった場合テスト成功とします.
IAssert.Assertの宣言は次のようになっています.
Public Sub Assert(ByVal result As Boolean, Optional Byval message As String = "")
resultがTrueの時テスト成功です.次のようにして利用します.
ast.Assert v.Dimention = 3, "VectorUtil.CreateVector(3).Dimention == 3"
IAssert.AssertEqualの宣言は次のようになっています.
Public Sub AssertEqual(ByVal expected As Variant, ByVal actual As Variant, ByVal message As String = "")
expectedとactualが等しいとき,テスト成功です.ここで,等しいの意味がオーバーローディングされていることに注意してください.普通の値の場合,等値テストは「expected = actual」という式で行われます.expectedとactualがともに浮動小数点型の値の場合,等値テストは「Abs(expected - actual) <= Eps」という式で行われます.両方ともオブジェクトの場合は(本当は無視したいのですが),等値テストは「expected Is actual」という式で行われます.特にオブジェクトの比較には注意してください.これは基本的に役に立ちません.
ast.Assert v.Dimention, 3, "Dimention of Vector" ast.Assert VectorUtil.Norm(v), 1.0, "|v| == 1.0"
MATSUMOTO Soutaro < soutaro@users.sourceforge.jp >
$Date: 2004-07-17 01:56:24 +0900 (Sat, 17 Jul 2004) $