Junit4でテストの順序を制御する
例えばinsertTestをしたあとにdeleteTestをするようなことをしたいなーというようなとき、JUnit3ではTestSuiteで行えた*1
junit3なら
import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; public class TestOrderForJunit3 extends TestCase { public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new TestOrderForJunit3().new DbTest("testInsert")); suite.addTest(new TestOrderForJunit3().new DbTest("testDelete")); return suite; } public class DbTest extends TestCase { public DbTest(String name) { setName(name); } public void testInsert() { System.out.print("insert"); } public void testDelete() { System.out.print("delete"); } } }
こんな感じ。
しかしこれをJUnit4のTestSuiteに置き換えようとしたとき、クラス単位で順序制御をするようなやり方はあったが
メソッド単位での制御を制御するやり方は見つからなかった。
なので最初に考えたのは1クラス1テストのクラスを作るやり方。
import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({ TestOrderForJunit4.InsertTest.class, TestOrderForJunit4.DeleteTest.class,}) public class TestOrderForJunit4 { public static class DeleteTest { @Test public void testDelete() { System.out.println("delete"); } } public static class InsertTest { @Test public void test2() { System.out.println("insert"); } } }
こんな感じ。
内部的にクラスを持たせてそれをSuiteClassesで呼び出すようなことをしたら出来た。
どうも内部のclassはstaticでないといけない模様。
なんだかスマートじゃないのでもうちょっと調べてみたらStackoverflowにそのものずばりなやり方があった
上のよりも下の@Orderのアノテーションを自作するのがとても良さ気
以下コード抜粋。
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Order { public int order(); }
で、それの順序制御をするクラス
OrderedRunner.java
import java.util.Collections; import java.util.Comparator; import java.util.List; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; public class OrderedRunner extends BlockJUnit4ClassRunner { public OrderedRunner(Class<?> klass) throws InitializationError { super(klass); } @Override protected List<FrameworkMethod> computeTestMethods() { List<FrameworkMethod> list = super.computeTestMethods(); Collections.sort(list, new Comparator<FrameworkMethod>() { @Override public int compare(FrameworkMethod f1, FrameworkMethod f2) { Order o1 = f1.getAnnotation(Order.class); Order o2 = f2.getAnnotation(Order.class); if (o1 == null || o2 == null){ return -1; } return o1.order() - o2.order(); } }); return list; } }
とこんなふうに準備をして
@RunWith(OrderedRunner.class) public class TestUseOdered { @Test @Order(order=2) public void deleteTest(){ System.out.println("delete"); } @Test @Order(order=1) public void insertTest(){ System.out.println("insert"); } }
とすると@Orderで指定した順序が若い方から実行される。素敵!