EclipseでJUnit 4を使ったユニットテスト(プレミアム編)

7093 ワード

一、高級Fixture
 
前の記事では、@Beforeと@Afterの2つのFixtureタグを紹介しました.大きなファイル(500メガを超える)の読み書きを担当するクラスがあり、彼のすべての方法はファイルを操作することです.すなわち、各メソッドを呼び出す前に、大きなファイルを開き、ファイルの内容を読み込む必要があります.これは絶対に時間のかかる操作です.@Beforeと@Afterを使用すると、テストのたびにファイルが読み込まれ、効率が低下します.ここでは、すべてのテストが開始されると、すべてのテストが終了した後にファイルを解放し、テストのたびにファイルを読むのではなく、すべてのテストが開始されることを望んでいます.JUnitの著者も明らかにこの問題を考慮し、@BeforeClassと@AfterClassの2つのFixtureを与えてこの機能を実現してくれた.名前から分かるように、この2つのFixtureで表記された関数は、テスト用例の初期化時のみ@BeforeClassメソッドを実行し、すべてのテストが実行された後、@AfterClassを実行して終了作業を行う.ここで注意してください.各テストクラスには、@BeforeClassまたは@AfterClassと表記されるメソッドが1つしかありません.このメソッドはPublicおよびStaticでなければなりません.
 
二、時間制限テスト.
 
私が初級編で示した例を覚えていますか.その平方根を求める関数はBugがあり、死の循環です.
    public void squareRoot(int n) {
        for (; ;) ;                 //Bug :    
    }
 
もしテスト中に死のサイクルに遭遇したら、あなたの顔には絶対に笑顔が現れません.そのため、論理が複雑で、ループが深くネストされているプログラムでは、デッドループが発生する可能性が高いため、予防措置を取らなければならない.時間制限テストは良い解決策です.私たちはこれらのテスト関数に実行時間を設定して、この時間を超えると、彼らはシステムに強制的に終了され、システムはまたあなたに関数の終了の原因がタイムアウトしたためであることを報告して、このようにあなたはこれらのBugを発見することができます.この機能を実現するには、@Testにパラメータを追加するだけでいいです.コードは次のとおりです.
 
@Test(timeout = 1000)

public void squareRoot() ...{

        calculator.squareRoot(4);

        assertEquals(2, calculator.getResult());

}
 
Timeoutパラメータは、ミリ秒単位で設定する時間を示しているので、1000は1秒を表します.
 
三、テスト異常
JAVAの異常処理もポイントなので、異常を投げ出す必要がある関数を書くことがよくあります.では、関数が異常を投げ出すべきだと思っていますが、投げていません.これはBugではありませんか.これはもちろんBugで、JUnitもそれを考慮して、私たちがこのようなBugを見つけるのを助けてくれました.たとえば,我々が書いた計算機クラスには除算機能があり,除数が0であれば必ず「0異常除去」を投げ出す.そのため、これらをテストする必要があります.コードは次のとおりです.
 
  @Test(expected = ArithmeticException.class)

   public void divideByZero() ...{

   calculator.divide(0);

   }
 
 
上記のコードに示すように、@Testタグのexpected属性を使用して、私たちが検査する異常を彼に渡す必要があります.これにより、JUnitフレームワークは私たちが指定した異常を投げたかどうかを自動的に検出することができます.
 
四、    Runner
皆さんはこの問題を考えたことがありますか?JUnitフレームワークにテストコードを提出した後、フレームワークはどのようにあなたのコードを実行しますか?答えはRunnerです.JUnitには多くのRunnerがあり、彼らはあなたのテストコードを呼び出す責任を負っています.それぞれのRunnerにはそれぞれの特殊な機能があります.必要に応じて異なるRunnerを選択してテストコードを実行します.おかしいと思うかもしれませんが、前にそんなに多くのテストを書いて、Runnerを明確に指定していませんか?これは、JUnitにデフォルトのRunnerがあるためです.指定していない場合、システムは自動的にデフォルトのRunnerを使用してコードを実行します.すなわち、次の2つのコードの意味は完全に同じです.
import org.junit.internal.runners.TestClassRunner;

import org.junit.runner.RunWith;

 

//        TestClassRunner,         

public class CalculatorTest {...} 

 

@RunWith(TestClassRunner.class)

public class CalculatorTest {...}
 
 
上記の例から分かるように、Runnerを指定するには@RunWithタグを使用し、指定したRunnerをパラメータとして渡す必要があります.もう1つ注意すべきことは,@RunWithは関数を修飾するのではなくクラスを修飾するために用いられることである.1つのクラスにRunnerが指定されている限り、このクラスのすべての関数はこのRunnerによって呼び出されます.最後に、該当するPackageが含まれていることを忘れないでくださいね.上の例はこの点をよく書いています.次に、他のRunner特有の機能をお見せします.
 
五、パラメトリックテスト.
このような関数に遭遇したことがあります.そのパラメータには多くの特殊な値があります.あるいは、彼のパラメータは多くの領域に分かれています.例えば、試験の点数を評価する関数で、戻り値はそれぞれ「優秀、良好、一般、合格、不合格」なので、試験を書くときは、少なくとも5つの試験を書いて、この5つの状況を含めて、これは確かに面倒なことです.また、以前の例を用いて、「1つの数の平方を計算する」という関数をテストし、正数、0、負数の3つに分類します.テストコードは次のとおりです.
 
import org.junit.AfterClass;

import org.junit.Before;

import org.junit.BeforeClass;

import org.junit.Test;

import static org.junit.Assert.*;

 
public class AdvancedTest ...{

private static Calculator calculator = new Calculator();

@Before
public void clearCalculator() ...{

        calculator.clear();
}

 

@Test
public void square1() ...{

        calculator.square(2);

        assertEquals(4, calculator.getResult());
}    
 

@Test   
public void square2() ...{

        calculator.square(0);

        assertEquals(0, calculator.getResult());
}


@Test   
public void square3() ...{

        calculator.square(-3);

        assertEquals(9, calculator.getResult());
}

}
 
 
似たようなテストを簡略化するため、JUnit 4は「パラメトリックテスト」という概念を提出し、テスト関数を1つだけ書いて、これらのいくつかの状況をパラメータとして伝え、一度にテストを完成させる.コードは次のとおりです.
 
import static org.junit.Assert.assertEquals;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.junit.runners.Parameterized;

import org.junit.runners.Parameterized.Parameters;

import java.util.Arrays;

import java.util.Collection;

 

@RunWith(Parameterized.class)
public class SquareTest ...{

private static Calculator calculator = new Calculator();

private int param;

private int result;    

 

@Parameters   
public static Collection data() ...{

        return Arrays.asList(new Object[][]{

                {2, 4},

                {0, 0},

                {-3, 9},

        });
}

 

//    ,        
public SquareTest(int param, int result) {

        this.param = param;
        this.result = result;
}

 

@Test   
public void square() {

        calculator.square(param);

        assertEquals(result, calculator.getResult());
}

}
 
 
次に、上記のコードを分析します.まず、このテストのために新しいクラスを生成し、他のテストと同じクラスを共有することはできません.この例では、SquareTestクラスを定義します.そして、このクラスにRunnerを指定して、デフォルトのRunnerを使用することはできません.特殊な機能は特殊なRunnerを使用する必要がありますから.@RunWith(Parameterized.class)この文は、このクラスにParameterizedRunnerを指定します.第2のステップでは、テスト対象のクラスを定義し、パラメータを格納するために2つの変数を定義し、期待される結果を格納するために1つの変数を定義します.次に,任意に命名できるテストデータの集合,すなわち前述のdata()メソッドを定義するが,@Parametersタグを用いて修飾しなければならない.この方法のフレームワークは説明されません.皆さんはその中のデータに注意しなければなりません.2次元配列で、データは2つのグループで、各グループのこの2つのデータは、1つはパラメータで、1つはあなたが予想した結果です.例えば,我々の第1のグループ{2,4}は,2がパラメータであり,4が予想される結果である.この2つのデータの順序はどうでもいいので、誰が前でも後でもいいです.その後はコンストラクション関数で、以前定義した2つのパラメータを初期化する機能があります.ここではパラメータの順序に注意し、上のデータセットの順序と一致させます.前の順序が{パラメータ,期待結果}であれば,あなたのコンストラクション関数の順序も「コンストラクション関数(パラメータ,期待結果)」であり,逆も同様である.最後に簡単なテスト例を書きますが、前に紹介した書き方と全く同じで、ここではあまり言いません.
 
六、梱包テスト.
前の紹介では、1つのプロジェクトでは、1つのテストクラスだけを書くことは不可能であり、多くのテストクラスを書くことができます.しかし、これらのテストクラスは一つ一つ実行しなければならないのも面倒なことです.これに鑑みて、JUnitは私たちにテストをパッケージ化する機能を提供して、すべての実行する必要があるテストクラスを集中して、一度に実行して、大いに私たちのテストの仕事を便利にしました.具体的なコードは以下の通りです.
 
import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({CalculatorTest.class, SquareTest.class})
public class AllCalculatorTests  {

}
 
この機能にも特殊なRunnerが必要であることがわかりますので、@RunWithタグにパラメータSuite.classを渡す必要があります.また、このクラスがパッケージテストクラスであることを示すために、@Suite.SuiteClassesという別のマークが必要です.パッケージするクラスをパラメータとしてこの寸法に渡せばいいです.この2つのマークアップがあれば、すべての意味を完全に表現しているので、次のクラスはもう重要ではありません.勝手にクラス名をつけて、内容はすべて空です.