是否可以将动态数量的参数传递给具有相同数据提供者的相同 testng 测试?

is it possible to pass dynamic number of parameters to same testng test with same dataprovider?

我有一个testng测试方法和一个数据提供者。我想让测试用例可用于具有待测试此功能的多个客户端。唯一的问题是该功能在不同客户端上的工作方式不同,我必须为不同客户端的同一功能提供不同数量的输入,最终结果对所有客户端都是相同的。

目前,我正在通过为具有此功能的多个客户端的数据提供者定义多个测试方法来做到这一点。

示例:-

@DataProvider(name="dp1")
public Object[][] getDataForClient1()
{
   //return data
}

@Test(dataProvider="dp1", groups={"client1"})
public void transferCredit(String senderId,String receiverId,String amount,String expectedResult)
{
   //Perform operation
}

@DataProvider(name="dp2")
public Object[][] getDataForClient2()
{
   //return data
}

@Test(dataProvider="dp2", groups={"client2"})
public void transferCredit(String senderId,String receiverId,String amount,String paymentReference,String expectedResult)
{
   //Perform operation
}

我开发了一个通用的测试逻辑来处理不同的参数集。我无法做的是对不同的参数集重复使用相同的测试方法。

我想像下面那样做

@DataProvider(name="dp")
public Object[][] getData()
{
   //return data
}

@Test(dataProvider="dp", groups={"client1,client2"})
public void transferCredit(String ... params)
{
   //Perform operation
}

但是这样做会导致参数不匹配的 testng 异常。那么在 TestNG 中有什么办法可以做到这一点吗?

不知道有一个非常 clean/straight 的转发功能可以使它易于访问,但很少有建议是 -

  1. 使用 DataProvider 中的数据超集,当您以不同的方法使用它们时,您可以忽略不需要所有参数的方法中的额外参数。示例 -

    @DataProvider(name="dp")
    public Object[][] getData() {
       //return data
    }
    
    @Test(dataProvider="dp1", groups={"client1"})
    public void transferCredit(String senderId,String receiverId,String amount,String expectedResult) {
       //Perform operation; Ignore paymentReference
    }
    
    @Test(dataProvider="dp", groups={"client2"})
    public void transferCredit(String senderId,String receiverId,String amount,String paymentReference,String expectedResult) {
        //Perform operation
    }
    
  2. 您可以使用 Method 获取 DataProvider 中调用方法的名称,并相应地调整您的 return 对象。这里的 documentation 和样本差不多。

    If you declare your @DataProvider as taking a java.lang.reflect.Method as first parameter, TestNG will pass the current test method for this first parameter. This is particularly useful when several test methods use the same @DataProvider and you want it to return different values depending on which test method it is supplying data for.

    @DataProvider(name="dp")
    public Object[][] getDataForClient2(Method m) {
       if(m.getName().equals("transferCreditM1") {
           //do X
       } else { 
           //do Y
       }     
    }
    

您可以将数据包装为一个对象。在我看来,有些参数保持不变,有些则发生变化。因此,创建一个 class,其中包含 senderid、receiverid、params 和所有这些都是超集 - 仅设置您需要的数据 - 基于调用数据提供者的方法并发送这些对象的数组。

另一种选择(除了已经在此处共享的选项之外)是做这样的事情

public class TestSample {

    @Test(dataProvider = "dp")
    public void testMethod(Object object) {
        if (object instanceof String[]) {
            System.err.println("Incoming array was " + Arrays.toString((String[]) object));
        }
        if (object instanceof String) {
            System.err.println("Incoming string " + object);
        }

    }

    @DataProvider(name = "dp")
    public Object[][] getData() {
        return new Object[][]{
                {new String[]{"TestNG", "JUnit"}},
                {"Cedric Beust"}
        };
    }
}

但老实说,我不认为这是一个可以在 TestNG 中接受的功能请求。仅代表个人意见。

读取已有的testng.xml文件,运行时修改并执行

以下代码的作用: 我想在运行时为每个参数添加一个参数列表。这些参数作为 Maven 运行时参数传递。使用 System.getProperty() 方法读取它们,如下所示。然后把这些参数加到里面,testng就是运行成功了。这可以根据您的要求进行扩展。

下面的代码读取 testng.xml 文件并将参数添加到

List<String> parameters = new ArrayList<>();
parameters = Arrays.asList(System.getProperty("parameters").split(",");

TestNG tng = new TestNG();
File initialFile = new File("testng.xml");
InputStream inputStream = FileUtils.openInputStream(initialFile);
Parser p = new Parser(inputStream);
List<XmlSuite> suites = p.parseToList();
for(XmlSuite suite:suites){
    List<XmlTest> tests = suite.getTests();
    for (XmlTest test : tests) {
         for (int i = 0; i < parameters.size(); i++) {
            HashMap<String, String> parametersMap = new HashMap<>();
            parametersMap.put("parameter",parameters.get(i));
            test.setParameters(parametersMap);
        }
    }
}
tng.setXmlSuites(suites);
tng.run();