JUnit のテストケースをステートフルで利用する

はじめに

JUnit で, 結合テスト (Integration test), シナリオテストを書きたい.

トランザクションごとに長いテストを書く必要がある.

複数のトランザクションを順に処理していったときに, オブジェクトの状態の変化を検証したい.

JUnit はテストケースが独立

はじめ, トランザクションごとにテストケースを書いていたが, うまく動かない.. オブジェクトの状態が初期化されてしまう.

これは, JUnit の設計思想だった.

つまり, 各テストケースは独立だということ. テストで使用するオブジェクトはテストケース内で生成されて, テストケース内で消滅する.

たとえば

たとえば, このテストは失敗する. number は 0 が入っている.

import static org.junit.Assert.*;

import org.junit.Test;

public class MemoryTest {

    static int number;

    @Test
    public void test () {
        number = 1;
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
    }
}

static を利用する

テスト間で状態を引き継ぐためには, 変数に static 修飾子をつける.

こうすると, 各テストケースの独立を破ることができる.

package test;

import static org.junit.Assert.*;

import org.junit.Test;

public class MemoryTest {

    static int number;
    static Foo foo;
    static Foo bar; 
    static Foo pee;     

    @Test
    public void test () {
        number = 1;
        foo = new Foo (1);
        bar = new Foo (foo);
        pee = new Foo ();       
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
        assertEquals (1, foo.i);
        assertEquals (1, bar.foo.i);        
        assertEquals (2, pee.foo.i);
        foo.plus (3);
    }

    @Test
    public void test3 () {
        assertEquals (4, foo.i);
    }

}

class Foo {
    public int i;
    public Foo foo;

    public Foo (int i) {
        this.i = i;
    }

    public Foo () {
        this.foo = new Foo (2);
    }

    public Foo (Foo foo) {
        this.foo = foo;
    }

    public void plus (int i){
        this.i += i;
    }
}

テストの実行順序を制御する

JUnit のテストが実行される順番はランダム.

これだと, ステートフルなテストには不向きだ.

テストの実行順序を指定するには, 以下の方法がある

  • @FixMethodOrder (MethodSorters.NAME_ASCENDING) をクラスの頭に設定
  • メソッド名を 実行したいものから abc 順に変更.
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.junit.FixMethodOrder;

@FixMethodOrder (MethodSorters.NAME_ASCENDING)
public class MemoryTest {

    static int number;
    static Foo foo;
    static Foo bar; 
    static Foo pee;     

    @Test
    public void test () {
        number = 1;
        foo = new Foo (1);
        bar = new Foo (foo);
        pee = new Foo ();       
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
        assertEquals (1, foo.i);
        assertEquals (1, bar.foo.i);        
        assertEquals (2, pee.foo.i);
        foo.plus (3);
    }

    @Test
    public void test3 () {
        assertEquals (4, foo.i);
    }

}