java - 如何在运行时动态地将测试组分配给测试方法以及@BeforeXXX和@AfterXXX注释的方法?

标签 java testng testng-dataprovider testng.xml testng-annotation-test

我的要求:

我的测试套件中有大约 100 个测试。

我不想在测试源代码中对组名称进行硬编码。

我想选择每次要运行的测试,但想从外部源传递该列表(csv/json/xml 等)通过 maven 命令发送到 TestNG 程序。

如果需要,我可以在源代码中进行参数化,如下所示:

@Test(groups = {"param1toBeReadFromExternalFile"})
@BeforeClass(groups = {"param1toBeReadFromExternalFile"})

这是可以在 TestNG 中实现的吗?

此要求的原因:

要求外部团队(无法访问源代码)能够使用特定组名称从 100 个测试中标记选择性测试,并动态运行测试,而无需 checkout 和 checkin 代码。

最佳答案

具体操作方法如下。

  1. 您首先构建 org.testng.IAnnotationTransformerorg.testng.IAlterSuiteListener 的实现
  2. 在此实现的构造函数中,您可以读取/解析包含分组映射方法的 JSON/CSV/XML/YAML 文件。
  3. transform() 方法中,您可以筛选出与传入方法匹配的方法,然后添加在 (2) 中的数据源文件中找到的组。
  4. alter() 中,您可以读取一个 JVM 参数,该参数暗示要过滤哪些组,然后相应地应用该过滤器。

这是一个完整的示例,它使用 Google Gson 库进行 json 解析。

这是我的测试类

package com.rationaleemotions.runtime;

import java.util.Arrays;
import java.util.stream.Collectors;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.Test;

public class DemoClass1 {

  @Test
  public void testMethod1() {
    printer();
  }

  @Test
  public void testMethod2() {
    printer();
  }

  private static void printer() {
    ITestResult itr = Reporter.getCurrentTestResult();
    System.err.println(itr.getMethod().getQualifiedName() + " belongs to the groups " +
        Arrays.stream(itr.getMethod().getGroups()).collect(Collectors.toList()));
  }
}

这是监听器的样子

package com.rationaleemotions.runtime;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.StreamSupport;
import org.testng.IAlterSuiteListener;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;
import org.testng.xml.XmlGroups;
import org.testng.xml.XmlRun;
import org.testng.xml.XmlSuite;

public class GroupChanger implements IAnnotationTransformer, IAlterSuiteListener {

  private JsonArray json;

  public GroupChanger() throws FileNotFoundException {
    String mapping = System.getProperty("mapping.file", "src/test/resources/file.json");
    if (!mapping.trim().isEmpty()) {
      json = JsonParser.parseReader(new FileReader(mapping))
          .getAsJsonArray();
    }
  }

  @Override
  public void alter(List<XmlSuite> suites) {
    String groupsToRun = System.getProperty("groups", "g1");
    if (groupsToRun.equalsIgnoreCase("*")) {
      //Execute everything. So don't add groups filtering in the suite file
      return;
    }
    for (XmlSuite suite: suites) {
      XmlGroups xmlGroups = new XmlGroups();
      XmlRun xmlRun = new XmlRun();
      for (String group : groupsToRun.split(",")) {
        xmlRun.onInclude(group);
      }
      xmlGroups.setRun(xmlRun);
      suite.setGroups(xmlGroups);
    }
  }

  @Override
  public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor,
      Method testMethod) {
    if (testMethod == null) {
      return;
    }
    if (json == null) {
      return;
    }
    String fqmn = testMethod.getDeclaringClass().getCanonicalName() + "." + testMethod.getName();
    StreamSupport.stream(json.spliterator(), true)
        .filter(each -> methodName(each).equalsIgnoreCase(fqmn))
        .findFirst()
        .ifPresent(each -> {
          System.err.println("Found " + each);
          annotation.setGroups(groups(each));
        });
  }

  private static String methodName(JsonElement each) {
    return each.getAsJsonObject().get("method").getAsString();
  }

  private static String[] groups(JsonElement each) {
    return each.getAsJsonObject().get("groupName").getAsString().split(",");
  }
}

套件文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="groups_suite" verbose="2">
  <listeners>
    <listener class-name="com.rationaleemotions.runtime.GroupChanger"/>
  </listeners>
  <test name="groups_test" verbose="2">
    <classes>
      <class name="com.rationaleemotions.runtime.DemoClass1"/>
    </classes>
  </test>
</suite>

这是 json 映射的样子

[
  {
    "method": "com.rationaleemotions.runtime.DemoClass1.testMethod1",
    "groupName": "g1"
  },
  {
    "method": "com.rationaleemotions.runtime.DemoClass1.testMethod2",
    "groupName": "g2"
  }
]

关于java - 如何在运行时动态地将测试组分配给测试方法以及@BeforeXXX和@AfterXXX注释的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73103242/

相关文章:

java - TestNg 注释语法

java - 倾城测试NG : Custom test method names while using @DataProvider

java - 如何识别数据提供者中的哪一行失败?

java - 为什么 String.toLowerCase() 返回的字符串没有被保留?

java - 如何拆分 ArrayList 并将数据存储到 android 中的 String 数组中?

java - 使用 testng 检测 @afterMethod 中跳过的测试

java - TestNG - 从不同的类导入/运行测试

java - 想要使用 TestNg 包运行 Maven 项目,但在执行项目时出现错误

Java:用于保存不同类型基元的通用集合

java - Spring boot 无法解析占位符 application.yml