第3回 C++アプリケーションの効率的なテスト手法(NUnit編):連載 C++開発者のための単体テスト入門(2/4 ページ)
C++のネイティブ・コードも.NETコードも同じように単体テストしたい!? それならNUnitが便利だ。そのテスト方法を紹介。
●NUnitの試運転:テストの作成
CSCounterTestプロジェクトに自動生成された「Class1.cs」ファイルの名前を「CounterTest.cs」に書き換え、下記のコードを書き込みます。
using System;
using NUnit.Framework; // (1)
using NUnit.Framework.SyntaxHelpers; // (2)
namespace NUnitDemo
{
[TestFixture] // (3)
public class CounterTest : AssertionHelper // (4)
{
private Counter counter;
[SetUp] // (5)
public void setUp()
{
counter = new Counter();
}
[TearDown] // (6)
public void tearDown()
{
}
[Test] // (7)
public void test_init()
{
Expect(counter.get(), Is.EqualTo(0)); // (8)
}
[Test] // (7)
public void test_incr()
{
for (int i = 1; i < 10; ++i)
{
counter.incr();
Expect(counter.get(), Is.EqualTo(i)); // (8)
}
}
[Test] // (7)
public void test_clear()
{
counter.incr();
counter.incr();
counter.clear();
Expect(counter.get(), Is.EqualTo(0)); // (8)
}
}
}
このコードの意味は以下のとおりです。
(1)(2) NUnit.Framework名前空間およびNUnit.Framework.SyntaxHelper名前空間の使用を宣言します。
CppUnitではテスト・コードに各種マクロを記述しましたが、NUnitでは属性(Attribute)を設定します。
(3) TestFixture属性を指定したpubilcクラス(class)は、それがひとまとまりのテスト(=テスト・フィクスチャ)であることを示します。NUnitはTestFixture属性の付けられたクラスをテストと認識し、実行します。
(4) AssertionHelperクラス(NUnit.Framework名前空間)を継承しておけば、後述するExpectメソッドを利用することができます。
(5)(6) SetUp属性およびTearDown属性の付いたpublicメソッドは、それぞれ各テストの開始直前/終了直後に呼ばれるので、ここに単体テストの前準備/後始末に必要なコードを書くことができます。いずれもパラメータや戻り値を持たないメソッドでなくてはなりません。この2つの属性は必須ではありません。この例では後始末に相当する処理は何も記述していませんから、実際にはTearDown属性を省略してもかまいません。ちなみに、テスト・フィクスチャ(=TestFixture属性が付いたクラス)全体に対する前準備/後始末を行うには、それぞれTestFixtureSetUp属性/TestFixtureTearDown属性を指定したメソッドを利用します。
(7) Test属性の付いたpublicメソッドが各テスト項目となります。SetUp属性/TearDown属性と同様に、パラメータや戻り値を持たないメソッドでなくてはなりません。
(8) Expectメソッドの呼び出しが結果の検証部です。CppUnitにおけるCPPUNIT_ASSERTマクロに相当します。Expectメソッドのパラメータで、さまざまな検証が可能です。以下にそのいくつかを挙げておきます。詳しくはNUnitのドキュメントを参照してください。
Expectメソッドのパラメータ指定 | 検証内容 |
---|---|
Expect(bool値) Expect(bool値, True) |
「bool値 = 真(True)」か? |
Expect(bool値, False) | 「bool値 = 偽(False)」か? |
Expect(結果値, EqualTo(期待値)) | 「結果値 = 期待値」か? |
Expect(結果値, Not.EqualTo(期待値)) | 「結果値 ≠ 期待値」か? |
Expect(結果値, GreaterThan(期待値)) | 「結果値 > 期待値」か? |
Expect(結果値, LessThan(期待値)) | 「結果値 < 期待値」か? |
Expect(結果値, EqualTo(期待値).Within(誤差)) | 浮動小数値に対し、結果値と期待値との差は誤差の範囲内か? |
Expectメソッドを使ったさまざまな検証方法 |
NUnitDemoソリューションをビルドし、CSCounterTestプロジェクトのアセンブリ(CSCounterTest.dllファイル)が生成されたところでさっそくテストしてみましょう。
●NUnitの試運転:テストの実行
デスクトップに置かれたNUnitアイコンをダブルクリックしてNUnitテストランナー(=TestRunner。GUI版のNUnit実行環境。実体は「nunit.exe」ファイル)を起動します。メニュー・バーから[File]−[Open Project]を選択し、[Open Project]ダイアログで「CSCounterTest.dll」を指定すると、CounterTestクラスで指定したテスト項目がツリー表示されます。
[Run]ボタンをクリックすることでテストが実行され、各テスト項目の成功/失敗が緑丸/赤丸で示されます。[Run]ボタンの下にあるプログレス・バーは、全テストが成功すれば緑、1つでも失敗すれば赤となります。次の画面は現段階でのテスト結果です。
テスト対象であるCounter.csファイルに修正を加え、再度ソリューションをビルドしてテストを繰り返し、全テストが成功してプログレス・バーが緑になればテスト完了です。
CppUnitやNUnitなどのxUnitは大量のテストを一気に、素早く、何度でも繰り返せるのが大きな特徴であり、メリットです。従ってテスト対象がユーザー・インターフェイス(UI)を含んでいると、テスト中にユーザー入力や目視チェックが混入し、テストの大量、高速実行を阻害することになります。
xUnitを活用することで効率と品質を向上させるつもりなら、アプリケーションをUI部とUIを含まないロジック部に分離し、ロジック部のみを単独でテストできる構造に仕立てることが重要な設計指針となります。
それでは、このNUnitを使ったC++のネイティブ・コードのテスト方法の話に移ります。
Copyright© Digital Advantage Corp. All Rights Reserved.