注解@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