JUnit 実践入門 体系的に学ぶユニットテストの技法 - 第3章 テスティングフレームワーク テストを支えるしくみ

第3章 テスティングフレームワーク テストを支えるしくみ

  • テストでは、入力値の準備や、期待される結果の検証が重要

3.1 テスティングフレームワークとは

  • 一定のフォーマットで書けるため、可読性に貢献
  • テストコードの記述に集中できる

xUnit フレームワーク

3.2 JUnit によるユニットテストの記法

テストソッドの throw 句

  • 記述は自由
  • 通常は、expected 句に Exception クラスを記述する
  • Java では一般に、メソッドの throw 句に、Throwable や Exception などの基底クラスを指定できない
    • JUnit では例外処理はフレームワークで行われるため、throw 句に各 Exception を詳細に書き込んだかどうかは、テストに影響を及ぼさない

テストメソッドを簡単に挿入する

  • Eclipse のテンプレート機能を利用

3.3 可読性の高いテストコードの書き方

  • テストコードは、プロダクションコード同様の整理をすべきではない
    • 独立したテストケースに対して、可読性が高いことを優先する

テストケース

  • 前提条件
  • 入力値・操作
  • 期待する値・動作

テスト対象

  • SUT System Under Test: テスト対象となるクラスやオブジェクト
  • 1 テストケースにつき、1 SUTを対象とする
  • テスト対象のインスタンス名を sut とかにするとわかりやすい

実測値と期待値

  • 実測値 actual value: メソッドが返す値や、オブジェクトの変化する状態など
  • 期待値 expected: 仕様として返すべき値や状態
    • 仕様変更がない限り不変
  • テストコードの変数名は actual, expected などがおすすめ

メソッドと副作用

以下の様な精子のメソッドはテストが容易で、「関数的」という

  • メソッドが戻り値を持つ
  • メソッドの呼び出しの結果、副作用がない
  • 同じ状態、同じパラメータで実行すれば、必ず同じ結果を返す

一方で ArrayList.add などは副作用があるものの代表。

  • size() や get() で状態を確認するしかない

テスト対象が乱数や時刻等で実測値が変化する場合、モックオブジェクトで状態を固定し、テストを実施する

4フェーズテスト

  • 以下の4フェーズを意識して書かれたテストは可読性が高い。特に事前準備とテスト実行。
    • 事前準備 set up
    • 実行 exercize
    • 検証 verify
    • 後処理 tear down

テストフィクスチャ test fixture

  • テスト実行時に必要なすべてのデータや状態
    • DB 初期化や複雑なデータは注意が必要で、準備部分が長くなって、テスト自体のコードが不鮮明になる
  • テストフィクスチャり準備のためのコードは簡潔に
    • 外出し(外部クラス、外部ファイルなど)

3.4 比較検証を行うアサーション

  • 実測・期待の比較のこと
  • JUnit では主に、org.junit.Assert クラスの assertThat メソッドと、Matcher API を利用してアサーションを記述する

JUnitアサーション

  • assertThat -> arg[1]:actual arg[2]: expected を含む Matcher オブジェクト
  • is メソッドで生成される Matcher オブジェクトはオブジェクトの同値性(equalsメソッドと同等)を検証する

3.5 JUnit が提供するアノテーション

  • アノテーション: Java 5 からの言語仕様。クラス、メソッド、変数などに補助的な情報を宣言するための機能。
  • JUnit では、@Test により、フレームワークが実行するテストメソッドを認識させている

@Test - テストメソッドを宣言する

  • expected
  • timeout
    • テスト失敗までの待ち時間を指定。一部分の実行がテスト全体を止め内容にするための保険
    • 性能テスト用ではない
  • 要求: 戻り値なし、引数なし、publicメソッド

@Ignore - テストの実行から除外する

  • テストクラスに付与すると、クラス単位で無視

@Before - テスト実行前に処理を行う

  • テストメソッド間で重複した初期化処理を定義する
  • メソッド名: setUp
  • 同一クラス内限定
  • 複数のクラスに適用したい場合は、『ルール』を使うこと
    • 継承は好ましくない
  • 要求: 返り値なし、引数なし、publicメソッド

@After - テスト実行後の後処理を行う

  • テストの成功失敗に関わらず必ず実行される
  • メソッド名: tearDown
  • 要求: 返り値なし、引数なし、publicメソッド

@BeforeClass - テスト実行前に一度だけ処理を行う

  • テストクラスがクラスローダに読み込まれたあと、そのテストが含まれる最初のテストが実行される前に一度だけ実行される
  • あまり使わない
    • テストメソッドは基本的に独立しているべきで、テストクラス単位ではなく、テスト単位でリソースの作成/開放を行うべきだから
  • 要求: 返り値なし、引数なし、static な publicメソッド

3.6 JUnit のテストパターン

  • 標準的な振る舞いを検証するテスト
    • ほとんどがこのパターンの4フェーズテスト
  • 例外の送出を検証するテスト
    • 送出される例外の型を Test アノテーションの expected 属性に記載
    • JUnit の例外検証では、例外の型以外は検証できない
      • より詳しくやりたければ、org.junit.rules.ExpectedException を利用する
  • コンストラクタを検証するテスト

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)