JUnit 実行順序、さらに範囲指定での実行

JUnit 実行順序を指定するだけだと、
JUnit テストケースの実行順序 - Oboe吹きプログラマの黙示録
この通りだが、さらにその実行順序を振った前提で順番の番号の範囲を指定して
実行するにはこれに、少し改良すれば良い

@Order アノテーションは前回と同じ

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Order
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Order {
    int value();
}

加えて新たに、テストクラスに付与させる実行順序番号による範囲を指定する
アノテーション

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * TestRange
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TestRange {
    int start() default 1;
    int end()   default 0;
}

そして、BlockJUnit4ClassRunnerを継承したソートを以下のように改良する。

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
/**
 * OrderedRunner
 */
public class OrderedRunner extends BlockJUnit4ClassRunner {
    private TestRange range;
    public OrderedRunner(Class<?> cls) throws InitializationError  {
        super(cls);
        range = cls.getAnnotation(TestRange.class);
    }
    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        List<FrameworkMethod> list = super.computeTestMethods();
        if (range==null) {
            return list.stream().sorted(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.value() - o2.value();
                }
            }).collect(Collectors.toList());
        }
        List<FrameworkMethod> res = list.stream().sorted(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.value() - o2.value();
            }
        }).collect(Collectors.toList());
        int end = range.end()==0 ? res.size() : range.end();
        return IntStream.rangeClosed(range.start(), end).boxed().map(i->res.get(i-1)).collect(Collectors.toList());
    }
}

@Order(10) から @Order(19) を実行したい場合

@RunWith(OrderedRunner.class)
@TestRange(start=10, end=19)
public class SampleTest{

@Order(20) 以降を実行したい場合

@RunWith(OrderedRunner.class)
@TestRange(start=20)
public class SampleTest{

@Order(30) までを実行したい場合

@RunWith(OrderedRunner.class)
@TestRange(end=30)
public class SampleTest{

これで、大量に作成したテストケースを一時的に任意の範囲で実行したい時は、
クラスアノテーション @TestRange で指定できる。
範囲指定しないで全て順番どおりに実行するときは、 @TestRangeをコメントアウトにすればよい。