【C#/NUnit/Moq】単体テストについて

背景

業務で利用しているNUnit・Moqを学習するにあたり、そもそも単体テストについての知識がないので単体テストの目的、手法、ライブラリの使い方などついて自分用にまとめます。

なお、単体テストは自動化されたテストを前提に記載しています。分類としての単体テストでは自動テストを必ずしも意味していないため。(手動の単体テストはマイナーだと思いますが)

単体テスト

比較的小さなプログラムのテスト。テスト対象は主にクラスやメソッドなどテスト可能な最小単位な部品(ユニット)。

メリット

  • バグの早期発見
    単体テストはコードの開発直後にテストするため、バグがあった場合にすぐに発見できる。
    またテスト対象の粒度が小さいため、問題があった箇所を特定しやすい。

  • 品質の維持
    リファクタリングや影響箇所の修正などで既存コードを改修した際に、テストコードがあれば改修による問題を発見・修正しやすくなるため品質を維持しやすい。

デメリット

  • 開発者の工数増加
    単体テストはテストコードだけではなく、テストコードを呼び出すドライバやテストコードから呼び出されるスタブなどの準備が必要となる。
    開発者は稼働するコード以外にも開発する必要があるため、開発工数が増加してしまう。

  • 後回しにされやすい
    開発者の負担増加によるスケジュールの関係で、網羅的ではなく簡易的なテストだけで済まされてしまう場合がある。またテストコードのメンテナンス漏れやテスト実行されなくなってしまう可能性もある。

他のテスト

単体テスト以外にも以下のテストがある。

  • 結合テスト
    単体テストの次に行うテストで複数のプログラムを組み合わせて正常に動作するか確認するテスト。
    部品ごとの動作を確認する単体テストは完了しているため、主にデータの受け渡しや流れを確認する。

  • システムテスト
    結合テストの次に行うテストで、ユーザーが使用する環境を想定して確認するテスト。
    1つの機能を確認する結合テストは完了しているため、外部のシステムや他の機能に影響がないかシステム全体を確認する。

単体テストの手法

ホワイトボックステスト

プログラムの内部構造(関数や条件分岐など)に関するテストで、テスト対象のソースコードが正常に動作するか確認するテスト。

網羅手法

  • 命令網羅
    全ての処理を最低1回でも通す。

  • 分岐網羅
    全ての分岐の処理を通す。(分岐先に注目したテスト)

  • 条件網羅
    全ての分岐条件の真/偽条件の場合の処理を通す。(分岐条件に注目したテスト)

ブラックボックステスト

プログラムの内部構造は意識せず、入力に対して期待される結果が仕様通りか確認するテスト。

分割法

  • 同値分割法
    有効な値、無効な値を入力して想定となる結果になるか。

  • 境界値分割法
    有効な値と無効な値の境界となる値を入力して想定となる結果になるか。

NUnit/Moq

NUnit

C#Visual Basicなど.NET言語の単体テストフレームワークJava単体テストフレームワークであるJUnitから派生して開発された。

Moq

.NETのための唯一のモックライブラリ、予め作成しておいたインターフェースに対して、テストする際の振る舞いを設定することができる。

以下Microsoftチュートリアルや業務でよく見かけるキーワードについて記載。

属性

テスト用のクラスやメソッドなどに付与する属性

  • Test
    TestFixtureクラス内のメソッドをテストとしてマーキングする。パラメーターを利用しない単純なテストに使われることが多い。

  • TestFixture
    テストとオプションでsetup, teardownメソッドを含むクラスをマーキングする。

  • Setup
    TestFixtureの内側で使われ、各Testメソッドの前に実行される共通処理を書くことが出来る。

  • TearDown
    TestFixtureの内側で使われ、各Testメソッドの後に実行される共通処理を書くことが出来る。

  • Ignore
    何らかの理由でテストを実行すべきではないときに、TestFixtureTestの属性に加えることで、付与したテストを無視できる。

  • TestCase
    テストメソッドにパラメータを渡し、渡したデータでテストが実行される。

アサーション

テスト結果を判定するための機能、テスト結果によって成功・失敗と判定される。

  • Assert.AreEqual
    2つの引数が同一か判定する

  • Assert.NotEqual
    2つの値が異なるか判定する

  • Assert.Throws
    特定の例外がthrowされることを確認する

  • Assert.DoesNotThrow
    特定の例外がthrowされないことを確認する

  • Assert.Fail
    失敗を生成する、またプロジェクトに合わせて失敗時のメッセージやパラメーターを設定できる。

モック

データベースアクセスやネットワーク通信など外部通信が行われるテストにおいて、テスト用の結果を返す代わりのオブジェクト。

注意点
事前にテストするクラス・メソッドのインターフェースを定義する必要がある。また本物のクラスもそのインターフェースを実装する。

  • Setup
    特定のメソッドが呼ばれた際の戻り値や例外などの指定ができる。 このメソッドでテスト時のオブジェクトの振る舞いを決定する。

検証用アプリ

参考