如何在运行多个测试用例中 TestNG 套件

⚡ 智能摘要

使用 TestNG 套房 Selenium 它允许您从单个 testng.xml 文件触发多个类、包或子测试套件。本演练涵盖并行线程、套件层次结构、报告和现代测试的 AI 辅助功能。 TestNG 7.x 项目。

  • 🧵 并行线程: 设置线程数和 parallel=”tests” 可以大幅缩短跨浏览器和软件包的整体运行时间。
  • 🗂️ 套件层级结构: 父级 testng.xml 文件可以列出子套件文件条目,从而在一个触发器中链接多个套件。
  • ⚙️ TestNG 7.x 版本已就绪: 示例与 TestNG 7.10和 Selenium 4 个 W3C 驱动程序,取代旧版驱动程序 Firefox驱动器接线。
  • 📊 智能报表: 1 到 10 级详细程度和可通过电子邮件发送的 HTML 报告有助于快速诊断并行线程故障。
  • 🤖 人工智能编排: AI 驱动的调度器根据历史不稳定性和持续时间数据对套件进行重新排序、重试和分片。

使用 TestNG 套房 Selenium

TestNG 它允许您在同一个项目中并行运行测试方法、类和完整的测试套件。并行执行可以降低总运行时间,因为线程会并发启动测试,而不是一个接一个地启动。本指南解释了如何使用它运行多个类(不同的测试套件)。 TestNG 7.x Selenium WebDriver。

步骤 1)创建 TestNG用于执行测试的 .xml 文件

要创建配置,请按照以下步骤操作。

  1. 创建一个新项目 Eclipse.
  2. 在项目中创建两个包(分别命名为: com.suite1com.suite2).
  3. 在每个包中创建一个类(并命名它们) Flipkart.javaSnapdeal.java)并将以下代码复制到相应的类中。
  4. 在你的项目中创建一个新文件,并将其命名为 测试ng.xml。 确保 TestNG 插件已安装(安装说明可用) 开始testng.xml 文件包含所有配置,例如类名、测试名和测试套件名。

Flipkart.java

package com.suite1;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class Flipkart {

    WebDriver driver = new FirefoxDriver();
    String username = ""; // Change to your username and password
    String password = "";

    // This method navigates to the Flipkart URL
    @BeforeClass
    public void init() {
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
        driver.navigate().to("https://www.flipkart.com");
    }

    // Log in to Flipkart
    @Test
    public void login() {
        driver.findElement(By.partialLinkText("Login")).click();
        driver.findElement(By.cssSelector(".fk-input.login-form-input.user-email")).sendKeys(username);
        driver.findElement(By.cssSelector(".fk-input.login-form-input.user-pwd")).sendKeys(password);
        driver.findElement(By.cssSelector(".submit-btn.login-btn.btn")).click();
    }

    // Search for a product
    @Test
    public void searchAndSelectProduct() {
        driver.findElement(By.id("fk-top-search-box")).sendKeys("moto g3");
        driver.findElement(By.cssSelector("search-bar-submit.fk-font-13.fk-font-bold")).click();
        String css = ".gd-row.browse-grid-row:nth-of-type(1) > div:nth-child(1)>div>div:nth-child(2)>div>a";
        driver.findElement(By.cssSelector(css)).click();
    }

    @Test
    public void buyAndRemoveFromCart() {
        driver.findElement(By.cssSelector(".btn-express-checkout.btn-big.current")).click();
        driver.findElement(By.cssSelector(".remove.fk-inline-block")).click();
        Alert a = driver.switchTo().alert();
        a.accept();
    }

    @Test
    public void logout() {
        Actions s = new Actions(driver);
        WebElement user = driver.findElement(By.partialLinkText(username));
        s.moveToElement(user).build().perform();
        driver.findElement(By.linkText("Logout")).click();
    }

    @AfterClass
    public void quit() {
        driver.close();
    }
}

SnapDeal.java

package com.suite2;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class SnapDeal {

    WebDriver driver = new FirefoxDriver();
    String username = ""; // Change to your username and password
    String password = "";
    String pinCode = "";

    // This method navigates to the Snapdeal URL
    @BeforeClass
    public void init() {
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
        driver.navigate().to("https://www.snapdeal.com");
    }

    @Test
    public void login() {
        driver.findElement(By.xpath("//button[text()='Login']")).click();
        driver.switchTo().frame("loginIframe");
        driver.findElement(By.cssSelector("div[onClick='getLoginForm()']")).click();
        driver.findElement(By.id("j_username")).sendKeys(username);
        driver.findElement(By.id("j_password_login")).sendKeys(password);
        driver.findElement(By.id("signin_submit")).click();
        driver.switchTo().defaultContent();
    }

    @Test
    public void searchAndSelectProduct() {
        driver.findElement(By.cssSelector(".col-xs-20.searchformInput.keyword")).sendKeys("iphone 6s");
        driver.findElement(By.cssSelector(".sd-icon.sd-icon-search")).click();
        String css = ".product_grid_row:nth-of-type(1)>div:nth-child(1)";
        driver.findElement(By.cssSelector(css)).click();
    }

    @Test
    public void buyAndRemoveFromCart() {
        driver.findElement(By.xpath("//li[contains(text(),'Silver')]")).click();
        driver.findElement(By.id("pincode-check")).sendKeys(pinCode);
        driver.findElement(By.id("buy-button-id")).click();
        driver.findElement(By.cssSelector("i[title='Delete Item']")).click();
        Alert a = driver.switchTo().alert();
        a.accept();
    }

    @Test
    public void logout() {
        driver.findElement(By.linkText("START SHOPPING NOW")).click();
        Actions s = new Actions(driver);
        WebElement user = driver.findElement(By.cssSelector(".sd-icon.sd-icon-user"));
        s.moveToElement(user).build().perform();
        driver.findElement(By.linkText("Logout")).click();
    }

    @AfterClass
    public void quit() {
        driver.close();
    }
}

TestNG。XML

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite thread-count="2" verbose="1" name="Gmail Suite" parallel="tests">

  <test name="flipkart">
    <classes>
      <class name="com.suite1.Flipkart"/>
    </classes>
  </test>

  <test name="Myntra">
    <classes>
      <class name="com.suite2.SnapDeal"/>
    </classes>
  </test>
</suite>

最终的项目结构如下例所示。

创建 TestNG用于执行测试的 .xml 文件

步骤 2)并行执行 TestNG

保存上述 XML 文件后,下一步是运行并行测试。代码如下所示。

并行执行 TestNG

1)线程数定义线程数 TestNG 可以并行执行。数值越高,同时运行的测试就越多,直至达到 CPU 限制。

2)冗长:在控制台中记录执行详情。允许的值范围为 1 到 10。值越高,生成的日志越详细、越细粒度。

3) 姓名套房名称。如下所示:“Gmail 套房”。

4)平行:讲述 TestNG 要并发运行的内容。有效值包括测试、类、方法或实例。默认值为 没有.

右键单击 testng.xml 文件并选择 运行方式 > TestNG 套件完成后,您将看到汇总结果。

当您执行上述代码时,您将得到以下输出。

输出:

并行执行 TestNG

1) testng.xml 中定义的测试套件的名称。

并行执行 TestNG

2) testng.xml 中定义的测试名称。

并行执行 TestNG

3) testng.xml 中声明的类的名称。

并行执行 TestNG

4) 在 .java 文件中使用 @Test 注解的方法名称。

并行执行 TestNG

SnapDeal 测试也采用相同的流程,因此两个类会同时执行。

步骤 3)从一个父 testng.xml 运行多个测试套件

大型项目中常见的需求是将多个 testng.xml 文件链接成一个触发器。 TestNG 7.x 支持引用子套件的父套件 套件文件 每个子程序都可以维护自己的线程数、监听器和参数,因此每个子程序都可以单独保存。将每个子程序套件分别保存,然后将父程序指向其路径。仅运行父程序文件。 Eclipse可以通过 Maven 或命令行进行安装。

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Parent Suite" parallel="tests" thread-count="4">
  <suite-files>
    <suite-file path="./flipkart-suite.xml"/>
    <suite-file path="./snapdeal-suite.xml"/>
  </suite-files>
</suite>

这种模式使回归测试、冒烟测试和健全性测试套件彼此独立,但又可重用。您还可以通过设置从 Maven Surefire 触发父文件。 <suiteXmlFile>parent-suite.xml</suiteXmlFile> 在插件配置中,这使得相同的并行布局能够在持续集成管道中工作。

步骤 4)并行最佳实践 TestNG 运行

  • 置顶 TestNG 7.x: 绝大部分储备使用 TestNG 7.10 或更高版本 Selenium 4 因此,符合 W3C 标准的驱动程序在各个线程中表现一致。
  • 避免共享状态: 移动 网络驱动程序 将字段放入 ThreadLocal 中,以便每个线程拥有自己的会话。
  • 调整线程数: 首先检查 CPU 核心数,然后观察可通过电子邮件发送的 HTML 报告和网格加载情况,再决定是否提高 CPU 核心数。
  • 隔离测试数据: 每个会话使用不同的用户、购物车和密码,以避免登录冲突。
  • 失败时截取屏幕截图: 它们通过一个连接起来 测试监听器 更快地调试不稳定的并行运行。
  • 使用人工智能辅助: 像工具一样 Testimmabl 和 CodiumAI 可以标记不稳定的测试,并在下次运行之前建议稳定的选择器。

结语

上面的例子展示了如何使用 TestNG 执行并行测试。 TestNG 7.x 版本允许您使用单个 XML 文件启动多个测试类、链接多个子测试套件并调整并行线程,因此非常方便。 Selenium 项目完成速度大大加快。

常见问题

将每个班级放在各自的班级中在 testng.xml 中插入标签,然后设置 parallel=”tests” 和线程数至少为 2。 TestNG 在不同的线程上启动两个测试,因此这些类是并发执行而不是顺序执行的。

是的。构建一个父套件,列出其中的子文件。每个子套件文件路径都运行自己的配置。这种模式在以下情况下有效: EclipseMaven Surefire 和 Gradle并由 TestNG 从 6 开始,包括当前的 7.x 版本。

parallel 属性接受测试、类、方法、实例或不接受任何选项。当每个选项都只包含测试时,请选择测试。 `@Test` 标签用于实现自包含、类隔离以及方法隔离(当单个 `@Test` 方法线程安全时)。默认值为 `none`,表示所有操作顺序执行。

使用线程局部变量或者在 `@BeforeMethod` 代码块中初始化驱动程序,而不是将其作为静态字段。这样,每个线程都拥有自己的浏览器会话,从而消除了导致并行崩溃的竞争条件。 TestNG 运行 Selenium 格。

AI 编排器会研究之前的运行数据来预测故障,隔离不稳定的测试,并重新排序运行缓慢的测试。诸如 Launchable 之类的平台, Testim,以及 mabl 插头 TestNG 因此,最有可能失败的测试套件会首先运行,从而缩短持续集成服务器上的反馈循环。

是的。Launchable 和 BuildPulse 中的 AI 驱动调度器会测量每个测试的历史持续时间和不稳定率,然后将 testng.xml 文件拆分成多个均衡的分片。每个分片运行在独立的代理上,因此总运行时间会缩短,而并行利用率却能保持较高水平。

总结一下这篇文章: