■名前空間と属性の修正
次に、名前空間と属性を変更する。NUnitの機能は、NUnit.Framework名前空間で提供されるが、Visual Studioでは、
Microsoft.VisualStudio.TestTools.UnitTesting名前空間
で提供される。
名前空間や属性の互換性は、Enterprise Libraryのソース・コードにヒントがある。Enterprise Libraryでは、条件付きコンパイルを使って、それ自身の単体テストがNUnitでも、Visual Studioでも動作するように作られているためだ。
以下のソース・コードは、Enterprise Libraryから抜粋したものだ。
#if !NUNIT
using Microsoft.VisualStudio.TestTools.UnitTesting;
#else
using NUnit.Framework;
using TestClass = NUnit.Framework.TestFixtureAttribute;
using TestInitialize = NUnit.Framework.SetUpAttribute;
using TestCleanup = NUnit.Framework.TearDownAttribute;
using TestMethod = NUnit.Framework.TestAttribute;
#endif
このソースを見ると、usingディレクティブを使って、NUnitの属性に別名を設定していることが分かる。例えば、NUnitでテスト・クラスに設定するTestFixture属性には「TestClass」という別名を指定して、Visual Studio用のテスト・コードがNUnitでも動作するようになっている。
つまり、NUnit用に作られたテスト・コードをVisual Studioで動作させるには、これと逆にNUnitで書かれたテスト・コードをVisual Studioで動くように別名を記述すればよい。
#define NUnit
#if NUnit
using NUnit.Framework;
#else
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute;
using SetUp = Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute;
using TearDown = Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute;
using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute;
#endif
[TestFixture()]
public class Class1Test
{
[SetUp()]
public void MyTestInitialize()
{
// テストごとの初期化処理
}
[TearDown()]
public void MyTestCleanup()
{
// テストごとの後処理
}
[Test()]
public void 足し算Test()
{
// テスト・コード
}
}
#Const NUnit = True
#If NUnit Then
Imports NUnit.Framework
#Else
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute
Imports SetUp = Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute
Imports TearDown = Microsoft.VisualStudio.TestTools.UnitTesting.TestCleanupAttribute
Imports Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute
#End If
<TestFixture()> _
Public Class Class1Test
<SetUp()> _
Public Sub MyTestInitialize()
' テストごとの初期化処理
End Sub
<TearDown()> _
Public Sub MyTestCleanup()
' テストごとの後処理
End Sub
<Test()> _
Public Sub 足し算Test()
' テスト・コード
End Sub
End Class
このように条件付きコンパイルを使用すれば、ほとんどのテスト・コードは、そのままVisual Studio用の単体テストとして実行することができるようになる。
■クラスの初期化と後処理を行うメソッド
ところで、上記のコードを見て、クラス全体の初期化と後処理を行う「TestFixtureSetUp」と「TestFixtureTearDown」がないことに気付いた人もいるのではないだろうか。属性の比較表でも示したが、Visual Studioにはそれぞれに対応する「ClassInitialize」属性と「ClassCleanup」属性が提供されている。しかしこれらは単純な置き換えでは対応できない。
まずTestFixtureSetUp属性(Visual StudioではClassInitialize属性)であるが、この属性を付与するメソッドは、NUnitではクラスのインスタンス・メソッドなのに対して、Visual Studioでは、静的メソッドである必要がある。従って、TestFixtureSetUp属性のメソッドで、テスト・クラスの変数を初期化したり、テスト対象クラスをインスタンス化したりしていた場合には、変数を静的(staticやShared)に変更するなどの必要がある。
さらには、Visual Studioでは、テストの状態を保持する「TestContext」というオブジェクトが採用されている。前編でも紹介した、データ駆動テストなどで使用されるオブジェクトだが、テスト・クラスの初期化では、このTestContextオブジェクトがパラメータとして渡されるため、メソッドにパラメータを追加する必要がある。
以下で、NUnitとVisual Studioのテスト・クラス初期化メソッドのシグネチャを比較する。
// NUnitのテスト・クラス初期化
[TestFixtureSetUp()]
public void MyClassInitialize()
// Visual Studioのテスト・クラス初期化
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
' NUnitのテスト・クラス初期化
<TestFixtureSetUp()> _
Public Sub MyClassInitialize()
' Visual Studioのテスト・クラス初期化
<ClassInitialize()> _
Public Shared Sub MyClassInitialize(ByVal testContext As TestContext)
テスト・クラスの後処理メソッドについては、TestContextオブジェクトは渡されないが、インスタンス・メソッドと静的メソッドの違いがある。
// NUnitのテスト・クラス後処理
[TestFixtureTearDown()]
public void MyClassCleanup()
// Visual Studioのテスト・クラス後処理
[ClassCleanup()]
public static void MyClassCleanup()
' NUnitのテスト・クラス後処理
<TestFixtureTearDown()> _
Public Sub MyClassCleanup()
' Visual Studioのテスト・クラス後処理
<ClassCleanup()> _
Public Shared Sub MyClassCleanup()
繰り返しになるが、ここで解説したような一般的なテスト・クラスを作成している場合、移行は比較的容易だ。しかし、MockオブジェクトなどのNUnit特有の機能をきちんと使い込んでいる場合には移行は難しい。その場合、おそらくVisual Studioの単体テスト機能では満足できないと思われるため、NUnitをそのまま使い続けることになるだろう。
Visual Studioの単体テスト機能の最大の特徴は、やはりIDEに完全に統合されている点だ。そのため、テストの実施や結果の確認は非常に容易である。それほど凝ったテスト・コードが必要とされないのであれば、ぜひ移行を検討してほしい。
本特集では、2回にわたりVS 2008の単体テスト機能について解説してきたが、最後に単体テストはどんなときに使用すべきかについて補足しておきたい。
ここまで解説してきたように、単体テストを実施することによって、メソッドやクラスの品質を高めることができる。単体テストは品質向上のための有益な手段であると断言できる。ただし、小規模な開発プロジェクトですべてのメソッドに対して単体テストを作成していては開発の工数が大幅に膨らんでしまう。
そのため、小規模な開発で単体テストを適用するのは、次のようなケースに限定するのが現実的であると筆者は考えている。
上記以外のメソッドやクラスの場合は、UIなどから実際に操作してテストを実施してもよいと考えている。逆に大規模になると、品質を保証するという意味でも自動テストが有効に機能する場合も多い。テストは品質を守るための手段であるため、手動であろうと自動であろうと確実にテストがパスすればよいというのが筆者のスタンスである。どこまでテストを自動化するかは、プロジェクトの特性や工数に応じてよく検討してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.