注解@FixMethodOrder可以指定单元测试方法的执行顺序

虽然他提供了三种排序方式,但是其实一般能用的也就MethodSorters.NAME_ASCENDING,即按方法名字母顺序执行。而其他两种方式最终测试类的执行顺序其实都是不可预测的。

MethodSorters.DEFAULT,按方法名HashCode值顺序执行。如果方法名的HashCode值一致,那么再按照MethodSorters.NAME_ASCENDING即按方法名字母顺序排序。为什么说这种排序方式是不可预测的,其实主要是需要根据方法名得到HashCode值然后进行排序,我们写单元测试时难道还要去计算下方法名的hashcode值从而知道测试类的排序吗?需要注意的是,这种排序方式不是随机的。因为这里按照方法名获取HashCode值,调用的是String类的hashCode方法,并不是调用Object的hashCode方法。String类重写了hashCode方法,按照某种算法计算得到字符串的hashcode值;如果调用的Object类的hashCode方法,那么执行顺序才是不确定的,因为Object类的hashCode方法是native method,依赖特定的操作系统,在不同操作系统上可能得到的hashCode值不同,在某个特定的操作系统上,测试类的执行顺序才是确定的。

MethodSorters.JVM,按照JVM得到的方法顺序执行,测试方法的执行顺序是不可预测的,即每次运行的顺序可能都不一样。查看了下最终是调用的native method getDeclaredMethods0 来获取到需要调用的单元测试方法的。实际测试结果,单元测试的执行顺序的确是随机的。

如果在一个测试类上添加了注解@FixMethodOrder,但是没有指定执行顺序,即按照MethodSorters.DEFAULT默认方式排序。

如果一个测试类上没有添加注解@FixMethodOrder,即按照JVM得到的方法顺序来执行。

注解@FixMethodOrder的定义如下,可以看到他是通过设置value属性值来设置排序方式的,默认MethodSorters.DEFAULT方式。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface FixMethodOrder {
    /**
     * Optionally specify <code>value</code> to have the methods executed in a particular order
     */
    MethodSorters value() default MethodSorters.DEFAULT;
}

枚举类MethodSorters中定义了支持的三种排序方式:

public enum MethodSorters {
    /**
     * Sorts the test methods by the method name, in lexicographic order,
     * with {@link Method#toString()} used as a tiebreaker
     *  按方法名字母顺序执行
     */
    NAME_ASCENDING(MethodSorter.NAME_ASCENDING),

    /**
     * Leaves the test methods in the order returned by the JVM.
     * Note that the order from the JVM may vary from run to run
     * 按照JVM得到的方法顺序,这里注释也提示了,执行顺序不是确定的
     */
    JVM(null),

    /**
     * Sorts the test methods in a deterministic, but not predictable, order
     * 按方法名HashCode值顺序执行,如果hash值大小一致,则按方法名字母顺序执行
     */
    DEFAULT(MethodSorter.DEFAULT);

    private final Comparator<Method> comparator;

    private MethodSorters(Comparator<Method> comparator) {
        this.comparator = comparator;
    }

    public Comparator<Method> getComparator() {
        return comparator;
    }
}

看这个枚举类,JVM方式排序时没有提供Comparator的实现。

看一下类MethodSorter中对这几种排序方式的定义:

public class MethodSorter {
    /**
     * DEFAULT sort order
     */
    public static final Comparator<Method> DEFAULT = new Comparator<Method>() {
        public int compare(Method m1, Method m2) {
            int i1 = m1.getName().hashCode();
            int i2 = m2.getName().hashCode();
            if (i1 != i2) {
                return i1 < i2 ? -1 : 1;
            }
            return NAME_ASCENDING.compare(m1, m2);
        }
    };

    /**
     * Method name ascending lexicographic sort order, with {@link Method#toString()} as a tiebreaker
     */
    public static final Comparator<Method> NAME_ASCENDING = new Comparator<Method>() {
        public int compare(Method m1, Method m2) {
            final int comparison = m1.getName().compareTo(m2.getName());
            if (comparison != 0) {
                return comparison;
            }
            return m1.toString().compareTo(m2.toString());
        }
    };

    /**
     * Gets declared methods of a class in a predictable order, unless @FixMethodOrder(MethodSorters.JVM) is specified.
     *
     * Using the JVM order is unwise since the Java platform does not
     * specify any particular order, and in fact JDK 7 returns a more or less
     * random order; well-written test code would not assume any order, but some
     * does, and a predictable failure is better than a random failure on
     * certain platforms. By default, uses an unspecified but deterministic order.
     *
     * @param clazz a class
     * @return same as {@link Class#getDeclaredMethods} but sorted
     * @see <a href="http://bugs.sun.com/view_bug.do?bug_id=7023180">JDK
     *      (non-)bug #7023180</a>
     */
    public static Method[] getDeclaredMethods(Class<?> clazz) {
        Comparator<Method> comparator = getSorter(clazz.getAnnotation(FixMethodOrder.class));

        Method[] methods = clazz.getDeclaredMethods();
        if (comparator != null) {
            Arrays.sort(methods, comparator);
        }

        return methods;
    }

    private MethodSorter() {
    }

    private static Comparator<Method> getSorter(FixMethodOrder fixMethodOrder) {
        if (fixMethodOrder == null) {
            return DEFAULT;
        }

        return fixMethodOrder.value().getComparator();
    }
}

看一下getDeclaredMethods方法,在JVM得到Methods数组之后,会根据单元测试类上的注解@FixMethodOrder配置的排序方式来进行排序。

Demo:

package com.xh.learning;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

/** 
 * <Description> <br> 
 *  
 * @author luoluocaihong<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate Dec 8, 2017 <br>
 * @since V8.1<br>
 * @see com.xh.learning <br>
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
//@FixMethodOrder(MethodSorters.JVM)
//@FixMethodOrder(MethodSorters.DEFAULT)
public class MyJunitTestOrder {

    @Test
    public void testAdd1() {
        System.out.println("testAdd");
    }

    @Test
    public void testQuery1() {
        System.out.println("testQuery");
    }

    @Test
    public void testMode1() {
        System.out.println("testMode");
    }

    @Test
    public void testDel1() {
        System.out.println("testDel");
    }
}

单元测试运行结果:
testAdd
testDel
testMode
testQuery

参考文档:

Junit测试方法执行顺序 http://blog.csdn.net/benjamin_whx/article/details/45869525

equal和hashcode的认识 https://zhuanlan.zhihu.com/p/19655110?utm_source=qq&utm_medium=social

从一个简单的main方法执行谈谈JVM工作机制 http://blog.csdn.net/architect0719/article/details/50486933

results matching ""

    No results matching ""