TestNG并发执行用例详解和范例

发表于:2019-1-29 16:05

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:df0128    来源:CSDN

  前言
  TestNG有多种并发方式支持,方法的并发,class级的并发,test级的并发等;
  根据实际应用可以灵活的配置和使用,下面分别对几种并发方法进行说明:
  一、方法级并发
  方法级并发即method级并发,此种并发方式需要将xml中的suite标签的parallel属性设置为methods并添加属性thread-count并设置其值,其会将所有的方法按照设定的并发数进行并发,譬如总共有4个测试用例,并发数设置为3,则会开三个线程,那么必然会有两个用例是在同一个线程内的,跟用例在哪个class内没关系,范例如下:
  测试用例类一ThreadTest.java:
   package com.demo.test.testng;
  import org.testng.annotations.Test;
  public class ThreadTest {
  @Test()
  public void test1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-1 thread id:"+id);
  }
  @Test
  public void test2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-2 thread id:"+id);
  }
  }
  测试用例类二ThreadTest2:
   package com.demo.test.testng;
  import org.testng.annotations.Test;
  public class ThreadTest2 {
  @Test()
  public void test1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test2-1 thread id:"+id);
  }
  @Test
  public void test2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test2-2 thread id:"+id);
  }
  }
  xml设置并发数为3,并发类型为methods:
   <xml version="1.0" encoding="UTF-8">
  <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="threadSuite" parallel="methods" thread-count="3">
  <test name="Test">
  <classes>
  <class name="com.demo.test.testng.ThreadTest"/>
  <class name="com.demo.test.testng.ThreadTest2"/>
  </classes>
  </test> <!-- Test -->
  </suite> <!-- Suite -->
  执行结果如下:
  [RemoteTestNG] detected TestNG version 6.10.0
  [TestNG] Running:
  D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml
  test1-1 thread id:12
  test2-1 thread id:14
  test1-2 thread id:13
  test2-2 thread id:13
  ===============================================
  threadSuite
  Total tests run: 4, Failures: 0, Skips: 0
  ===============================================
  如上图所示,确实是开了三个线程,且有两个相同线程号的用例并非同一个测试类;
  二、class级并发
  此并发方式需要将xml中的suite标签内的属性parallel属性设置为classes,且添加属性thread-count并设置其值即可实现class级别并发,其会一个class内的所有方法放在一个线程内,根据线程数设置和总的class数来分配线程,譬如如果设置线程数为3,而class数目为2,则会开两个线程来分别运行两个class,而如果设置线程数为3,且class数目为4则将会有两个class在一个线程内,如下为一个简单的范例:
  两个用例类如下:
  ThreadTest.java
   package com.demo.test.testng;
  import org.testng.annotations.Test;
  public class ThreadTest {
  @Test()
  public void test1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-1 thread id:"+id);
  }
  @Test
  public void test2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-2 thread id:"+id);
  }
  }
  ThreadTest2.java
   package com.demo.test.testng;
  import org.testng.annotations.Test;
  public class ThreadTest2 {
  @Test()
  public void test1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test2-1 thread id:"+id);
  }
  @Test
  public void test2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test2-2 thread id:"+id);
  }
  }
  测试xml如下:
   <xml version="1.0" encoding="UTF-8">
  <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="threadSuite" parallel="classes" thread-count="3" verbose="2">
  <test name="Test">
  <classes>
  <class name="com.demo.test.testng.ThreadTest"/>
  <class name="com.demo.test.testng.ThreadTest2"/>
  </classes>
  </test> <!-- Test -->
  </suite> <!-- Suite -->
   运行结果:
  [RemoteTestNG] detected TestNG version 6.10.0
  ...
  ... TestNG 6.10 by Cédric Beust (cedric@beust.com)
  ...
  [TestNG] Running:
  D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml
  [TestRunner] Starting executor for test Test with time out:2147483647 milliseconds.
  test2-1 thread id:13
  test1-1 thread id:12
  test2-2 thread id:13
  test1-2 thread id:12
  PASSED: test1
  PASSED: test1
  PASSED: test2
  PASSED: test2
  ===============================================
  Test
  Tests run: 4, Failures: 0, Skips: 0
  ===============================================
  可以看到两个类分别开了一个线程,同一个类中的用例在同一个线程内,符合预期;
  那么如果有一个suite下有多个test,这个并发设置会否将所有的test都计算在呢?来试一下,新添加一个测试用例Depend1.java:
   package com.demo.test.testng;
  import org.testng.Assert;
  import org.testng.annotations.Test;
  public class DependTest1 {
  @Test(groups= {"dependGroup1"})
  public void dependTest1()
  {
  System.out.println("dependTest1");
  }
  @Test(groups= {"dependGroup1"})
  public void dependTest2()
  {
  System.out.println("dependTest2");
  }
  @Test(groups="dependGroup2")
  public void dependTest4()
  {
  System.out.println("dependTest4");
  Assert.assertFalse(false);
  }
  }
  修改xml为如下:
   <xml version="1.0" encoding="UTF-8">
  <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="threadSuite" parallel="classes" thread-count="2" verbose="2">
  <test name="Test1">
  <classes>
  <class name="com.demo.test.testng.ThreadTest"/>
  <class name="com.demo.test.testng.ThreadTest2"/>
  </classes>
  </test> <!-- Test -->
  <test name="test2">
  <classes>
  <class name="com.demo.test.testng.DependTest1">
  </class></classes>
  </test>
  </suite> <!-- Suite -->
  再次运行结果如下:
   [RemoteTestNG] detected TestNG version 6.10.0
  ...
  ... TestNG 6.10 by Cédric Beust (cedric@beust.com)
  ...
  [TestNG] Running:
  D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml
  [TestRunner] Starting executor for test Test1 with time out:2147483647 milliseconds.
  test2-1 thread id:13
  test1-1 thread id:12
  test2-2 thread id:13
  test1-2 thread id:12
  PASSED: test1
  PASSED: test1
  PASSED: test2
  PASSED: test2
  ===============================================
  Test1
  Tests run: 4, Failures: 0, Skips: 0
  ===============================================
  [TestRunner] Starting executor for test test2 with time out:2147483647 milliseconds.
  dependTest1
  dependTest2
  dependTest4
  PASSED: dependTest1
  PASSED: dependTest2
  PASSED: dependTest4
  ===============================================
  test2
  Tests run: 3, Failures: 0, Skips: 0
  ===============================================
  ===============================================
  threadSuite
  Total tests run: 7, Failures: 0, Skips: 0
  ===============================================
  可以看到是先运行test1(内含两个测试类),开了两个线程,而后再运行test2(内含一个测试类),开了一个线程,而这两个test内的三个class是并没有放在一起运行的;
  故这种并发设置是根据每个test标签生效的;
  三、test级并发
  test级并发为将xml中每个test标签下的用例放在一个线程内并根据并发数和tet数目开线程的并发方法,需要将xml中的suite标签内的属性parallel属性设置为tests,且添加属性thread-count并设置其值即可,譬如有一个suite下有两个test且并发数设置为2,那么就会开两个线程,每个线程都包含一个test,范例如下:
  ThreadTest.java:
   package com.demo.test.testng;
  import org.testng.annotations.Test;
  public class ThreadTest {
  @Test()
  public void test1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-1 thread id:"+id);
  }
  @Test
  public void test2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-2 thread id:"+id);
  }
  }
  ThreadTest2.java:
   package com.demo.test.testng;
  import org.testng.annotations.Test;
  public class ThreadTest2 {
  @Test()
  public void test1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test2-1 thread id:"+id);
  }
  @Test
  public void test2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test2-2 thread id:"+id);
  }
  }
  修改DependTest1.java:
   package com.demo.test.testng;
  import org.testng.Assert;
  import org.testng.annotations.Test;
  public class DependTest1 {
  @Test(groups= {"dependGroup1"})
  public void dependTest1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("dependTest1 id:"+id);
  }
  @Test(groups= {"dependGroup1"})
  public void dependTest2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("dependTest2 id:"+id);
  }
  @Test(groups="dependGroup2")
  public void dependTest4()
  {
  long id = Thread.currentThread().getId();
  System.out.println("dependTest4 id:"+id);
  Assert.assertFalse(false);
  }
  }
   xml设置如下:
   <xml version="1.0" encoding="UTF-8">
  <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="threadSuite" parallel="tests" thread-count="2" verbose="2">
  <test name="Test1">
  <classes>
  <class name="com.demo.test.testng.ThreadTest"/>
  <class name="com.demo.test.testng.ThreadTest2"/>
  </classes>
  </test> <!-- Test -->
  <test name="test2">
  <classes>
  <class name="com.demo.test.testng.DependTest1">
  </class></classes>
  </test>
  </suite> <!-- Suite -->
  运行结果:
   [RemoteTestNG] detected TestNG version 6.10.0
  ...
  ... TestNG 6.10 by Cédric Beust (cedric@beust.com)
  ...
  [TestNG] Running:
  D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml
  [ThreadUtil] Starting executor timeOut:2147483647ms workers:2 threadPoolSize:2
  dependTest1 id:13
  test1-1 thread id:12
  test1-2 thread id:12
  dependTest2 id:13
  test2-1 thread id:12
  dependTest4 id:13
  test2-2 thread id:12
  PASSED: test1
  PASSED: test2
  PASSED: test1
  PASSED: test2
  ===============================================
  Test1
  Tests run: 4, Failures: 0, Skips: 0
  ===============================================
  PASSED: dependTest1
  PASSED: dependTest2
  PASSED: dependTest4
  ===============================================
  test2
  Tests run: 3, Failures: 0, Skips: 0
  ===============================================
  ===============================================
  threadSuite
  Total tests run: 7, Failures: 0, Skips: 0
  ===============================================
  可见两个test是开了两个线程运行的,且同一个test内的用例都在同一个线程内;
  四、instances级并发
  此并发方法与前面几种并发方法类似,只是需要修改parallel为instances即可,为一个实例一个并发,范例如下:
   package com.demo.test.testng;
  import java.util.ArrayList;
  import java.util.List;
  import org.testng.annotations.Factory;
  import org.testng.annotations.Test;
  public class FactoryTest {
  private String host;
  private int port;
  public FactoryTest(String host, int port)
  {
  this.host=host;
  this.port=port;
  }
  @Test
  public void login()
  {
  long id = Thread.currentThread().getId();
  System.out.println("login, host:"+host+";port"+port+";id:"+id);
  }
  @Test(dependsOnMethods="login")
  public void logout()
  {
  long id = Thread.currentThread().getId();
  System.out.println("logout, host:"+host+";port"+port+";id:"+id);
  }
  @Factory
  public static Object[] create()
  {
  List<FactoryTest> list = new ArrayList<FactoryTest>();
  list.add(new FactoryTest("10.10.10.1", 8080));
  list.add(new FactoryTest("10.10.10.2", 8080));
  return list.toArray();
  }
  }
  xml如下:
   <xml version="1.0" encoding="UTF-8">
  <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  <suite name="threadSuite" parallel="instances" thread-count="4" verbose="2">
  <test name="Test1">
  <classes>
  <class name="com.demo.test.testng.FactoryTest" />
  </classes>
  </test>
  </suite> <!-- Suite -->
  运行结果如下:
   [RemoteTestNG] detected TestNG version 6.10.0
  ...
  ... TestNG 6.10 by Cédric Beust (cedric@beust.com)
  ...
  [TestNG] Running:
  D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml
  [TestRunner] Starting executor for test Test1 with time out:2147483647 milliseconds.
  login, host:10.10.10.1;port8080;id:12
  login, host:10.10.10.2;port8080;id:13
  logout, host:10.10.10.1;port8080;id:14
  logout, host:10.10.10.2;port8080;id:15
  PASSED: login
  PASSED: login
  PASSED: logout
  PASSED: logout
  ===============================================
  Test1
  Tests run: 4, Failures: 0, Skips: 0
  ===============================================
  ===============================================
  threadSuite
  Total tests run: 4, Failures: 0, Skips: 0
  ===============================================
  如上log可知,两个用例,两组参数,共四条用例开了四个线程,每个用例都是一个实例;
  如果是没有@Factory注解的普通用例,则没效果。
  五、测试用例级并发
  此级并发可以直接在用例内设置,如下为一个范例:
   package com.demo.test.testng;
  import org.testng.annotations.Test;
  public class ThreadTest {
  @Test(threadPoolSize = 3, invocationCount = 6, timeOut = 1000)
  public void test1()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-1 thread id:"+id);
  }
  @Test
  public void test2()
  {
  long id = Thread.currentThread().getId();
  System.out.println("test1-2 thread id:"+id);
  }
  }
  如上图代码所示,test1设置线程数为3,调用次数为6,超时时间为1000ms,运行结果如下:
  [RemoteTestNG] detected TestNG version 6.10.0
  [TestNG] Running:
  C:\Users\dufei\AppData\Local\Temp\testng-eclipse--1263110808\testng-customsuite.xml
  [ThreadUtil] Starting executor timeOut:1000ms workers:6 threadPoolSize:3
  test1-1 thread id:13
  test1-1 thread id:14
  test1-1 thread id:12
  test1-1 thread id:14
  test1-1 thread id:13
  test1-1 thread id:12
  test1-2 thread id:1
  PASSED: test1
  PASSED: test1
  PASSED: test1
  PASSED: test1
  PASSED: test1
  PASSED: test1
  PASSED: test2
  ===============================================
  Default test
  Tests run: 7, Failures: 0, Skips: 0
  ===============================================
  ===============================================
  Default suite
  Total tests run: 7, Failures: 0, Skips: 0
  ===============================================
  [TestNG] Time taken by org.uncommons.reportng.HTMLReporter@1d371b2d: 48 ms
  ---------------------
  如上所示,test1为三个线程,调用六次,超时为1000ms,符合预期;

     上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号