既然是讨论执行顺序问题,那么用例肯定是批量执行的,批量执行的方法有mvn test、直接运行testng.xml文件,其中直接运行testng.xml文件的效果与pom文件中配置执行testng.xml效果是一样,所以本次只讨论mvn test 批量运行方式
一、用例准备
1、 测试用例
编写一些测试用例,单纯为了测试,内容只进行输入,没有任何逻辑。
public class FirstTest {
@Test
public void testFirst(){
System.err.println("first test");
}
}
|
2、pom文件配置
要使用mvn test方式批量运行用例,需要在pom文件中配置一下内容
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
</plugin>
</plugins>
</build>
|
二、执行顺序梳理
1、mvn test 默认顺序
如果pom文件只是进行了上步骤的配置,那么执行mvn test,用例是多线程无序执行的,如果要按顺序执行要配置为单线程,在<plugin>标签内增加如下配置
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
|
再次执行mvn test,我们会发现用例是单线程,按一定顺序执行的。但是是按照字母a-z的顺序执行的,其实这个排序对我们来说用处不大,我们写用例要求的是看名知意,不可能按照这个顺序来写。
2、priority 注解
testng提供了丰富的注解功能,priority标示用例执行的优先级,默认值为0,值越大优先级越低。比如:
public class FirstTest {
@Test(priority = 2)
public void testFirst(){
System.err.println("first test");
}
}
public class SecondTest {
@Test
public void testFirst(){
System.err.println("second test");
}
}
public class ThirdTest {
@Test(priority = 1)
public void testFirst() {
System.err.println("third test");
}
}
执行结果:
second test
third test
first test
|
该注解对同一个类的多个方法也是适用的,比如:
public class FirstTest {
@Test(priority=2)
public void testFirst2(){
System.err.println("first test2");
}
@Test(priority=3)
public void testFirst3(){
System.err.println("first test3");
}
@Test(priority=1)
public void testFirst(){
System.err.println("first test");
}
}
执行结果:
first test
first test2
first test3
|
那么我们就会想如果每个类中都有多个方法,且优先级是不同的,那么执行顺序又是怎么样的?比如:
public class FirstTest {
@Test(priority=2)
public void testFirst2(){
System.err.println("first test2");
}
@Test
public void testFirst3(){
System.err.println("first test3");
}
@Test(priority=1)
public void testFirst(){
System.err.println("first test1");
}
}
public class SecondTest {
@Test
public void testFirst(){
System.err.println("second test");
}
}
public class ThirdTest {
@Test(priority = 1)
public void testFirst() {
System.err.println("third test");
}
@Test(priority = 2)
public void testFirst2() {
System.err.println("third test 2");
}
}
运行结果:
first test3
second test
first test1
third test
first test2
third test 2
|
这种情况我们从结果可以看出并没有按照类的顺序执行,而是按照priority设置的等级高低,去执行的类。那么这个问题的原因是什么?有没有办法类按照顺序执行同时类中方法也按照顺序执行?这个问题我们放到后面讨论解决方法。
3、dependsOnGroups
public class FirstTest {
@Test(dependsOnGroups={"second"})
public void testFirst(){
System.err.println("first test");
}
}
public class SecondTest {
@Test(groups="second",dependsOnGroups={"third"})
public void testFirst(){
System.err.println("second test");
}
public class ThirdTest {
@Test(groups="third")
public void testFirst() {
System.err.println("third test");
}
}
执行结果:
third test
second test
first test
|
同样该方法适用于类的方法,比如:
public class FirstTest {
@Test(dependsOnGroups={"first"},groups="second")
public void testFirst2(){
System.err.println("first test2");
}
@Test(groups="first")
public void testFirst3(){
System.err.println("first test3");
}
@Test(dependsOnGroups={"second"})
public void testFirst(){
System.err.println("first test1");
}
}
执行结果:
first test3
first test2
first test1
|
4、dependsOnMethods
该方法只适用于同一个类的不同方法间,不能跨类适用。举例如:
public class Third10Test {
@Test(dependsOnMethods = { "testFirst3" })
public void testFirst1() {
System.err.println("third10 test1");
}
@Test
public void testFirst2() {
System.err.println("third10 test2");
}
@Test(dependsOnMethods = { "testFirst2" })
public void testFirst3() {
System.err.println("third10 test3");
}
}
执行结果:
third10 test2
third10 test3
third10 test1
|
5、testng.xml
pom文件中在maven-surefire-plugin插件增加配置如下:
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
|
testng.xml作为testng的灵魂,提供了很强大的配置功能,其它使用方式可以自己百度。本问只讨论类型的执行顺序问题。tesng.xml配置如下:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1" >
<test name="Nopackage">
<classes>
<class name="com.appiumforatk.SecondTest" />
<class name="com.appiumforatk.FirstTest" />
<class name="com.appiumforatk.ThirdTest" />
</classes>
</test>
</suite>
|
执行mvn test 结果如下:
Second test
first test
third test
从结果可以看出,默认是按照顺序执行。其实在suite和test标签分别有preserve-order控制各自子标签的执行顺序,该值默认true。
如果我们把该值设置为false,可以看到用例不再按照配置的顺序执行了。如下:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1" >
<test name="Nopackage" preserve-order="false">
<classes >
<class name="com.appiumforatk.SecondTest" />
<class name="com.appiumforatk.FirstTest" />
<class name="com.appiumforatk.ThirdTest" />
</classes>
</test>
</suite>
|
执行mvn test命令,结果如下:
first test
Second test
third test
那么我们开始思考,如果testng.xml中设置了preserve-order= “true”,同时我们也设置了priority,那么执行顺序会怎么样?比如:我们只在SecondTest上加了priority=1,其它保持不变。
public class SecondTest {
@Test
public void testFirst(){
System.err.println("Second test");
}
@Test(priority = 1)
public void testFirst1(){
System.err.println("Second test1");
}
}
public class ThirdTest {
@Test
public void testFirst() {
System.err.println("third test");
}
@Test(priority = 1)
public void testFirst1() {
System.err.println("third test1");
}
}
|
mvn test执行结果如下:
Second test
first test
third test
Second test1
third test1
从结果可以看出同一priority优先级方法,按照配置的顺序执行。也即priority的优先级>preserve-order.那么我们回到2中的问题,原因是因为priority是在testng开始的时候全部加载进去,如果想实现按顺序执行完一个类的方法后,再执行另外一个类的方法,就要去改变方法的priority值,可以通过监听的方式实现。代码如下:
public class RePrioritizingListener implements IAnnotationTransformer {
HashMap<Object, Integer> priorityMap = new HashMap<Object, Integer>();
Integer class_priorityCounter = 10000;
Integer max_testpriorityLength = 4;
@Override
public void transform(ITestAnnotation annotation, Class testClass,
Constructor testConstructor, Method testMethod) {
Class<?> declaringClass = testMethod.getDeclaringClass();
Integer test_priority = annotation.getPriority();
Integer current_ClassPriority = priorityMap.get(declaringClass);
// 如果类没有设置过优先级,则进行设置。
if (current_ClassPriority == null) {
current_ClassPriority = class_priorityCounter++;
priorityMap.put(declaringClass, current_ClassPriority);
}
//获取类中方法的优先级,如果小于四位数则左侧补充0以达到四位数
String concatenatedPriority = test_priority.toString();
while (concatenatedPriority.length() < max_testpriorityLength) {
concatenatedPriority = "0" + concatenatedPriority;
}
//把类的优先级和方法的优先级合并
concatenatedPriority = current_ClassPriority.toString()
+ concatenatedPriority;
//重新设置方法的优先级
annotation.setPriority(Integer.parseInt(concatenatedPriority));
}
}
|
testng.xml配置如下:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1" >
<test name="Nopackage" preserve-order="true">
<classes >
<class name="com.appiumforatk.SecondTest" />
<class name="com.appiumforatk.FirstTest" />
<class name="com.appiumforatk.ThirdTest" />
</classes>
</test>
<listeners> //配置监听
<listener class-name="com.appiumforatk.RePrioritizingListener"/>
</listeners>
</suite>
|
mvn test执行命令结果如下:
Second test
Second test1
first test
third test
third test1
这个时候我们看到按照配置的顺序执行class并且class中的方法也是按照priority优先级执行的。