数据提供者 & TestNG XML:参数化 Selenium(例子)

当我们开发软件时,我们总是希望它能够根据不同的数据集以不同的方式工作。当涉及到 测试 对于同一款软件,我们不能只用一组数据来测试它。在这里,我们再次需要验证我们的系统是否采用了预期支持的所有组合。为此,我们需要参数化我们的测试脚本。图中出现了参数化。

参数化于 Selenium

参数化于 Selenium 是参数化测试脚本的过程,以便在运行时将多个数据传递给应用程序。这是一种使用不同值自动多次运行测试用例的执行策略。通过参数化测试脚本实现的概念称为 数据驱动测试.

参数化类型 TestNG-

为了使参数化更加清晰,我们将介绍最流行的框架之一中的参数化选项 Selenium Webdriver – TestNG.

这里有 两种方式 通过它可以实现参数化 TestNG

  1. 的帮助下 参数 注解TestNG XML 文件中。

    参数化类型 TestNG

  2. 的帮助下 数据提供者 注解。

    参数化类型 TestNG

参数化类型 TestNG

Testng.xml 中的参数可以是套件或测试级别

DataProvider 中的参数可以以 Method 和 ITestContext 作为参数。

让我们详细研究一下——

参数注释 TestNG

参数注释 TestNG 是一种使用 .xml 文件将值作为参数传递给测试方法的方法。用户可能需要在运行时将值传递给测试方法。@Parameters 注释方法可用于任何具有 @Test、@Before、@After 或 @Factory 注释的方法。

使用Testng.xml进行参数注释

当您确实想要处理复杂性且输入组合数量较少时,请选择使用注释进行参数化。

让我们看看它是如何工作的

测试场景

步骤 1)启动浏览器并转到 Google.com

步骤2)输入搜索关键字

使用 Testng.Xml 进行参数注释

步骤 3)验证输入的值是否与测试数据提供的值相同

步骤 4)重复 2 和 3,直到输入所有值

测试作者 搜索关键字
Guru99 印度
Krishna 美国
布佩什 中国

这是一个不使用参数的示例

package parameters;

import org.testng.annotations.Test;
import org.testng.AssertJUnit;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class NoParameterWithTestNGXML {
	String driverPath = "C:\\geckodriver.exe";
	WebDriver driver;
    
    @Test
    public void testNoParameter() throws InterruptedException{
        String author = "guru99";
        String searchKey = "india";
        
        System.setProperty("webdriver.gecko.driver", driverPath);        
        driver= new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        
        driver.get("https://google.com");
        WebElement searchText = driver.findElement(By.name("q"));
        //Searching text in google text box
        searchText.sendKeys(searchKey);
        
        System.out.println("Welcome ->"+author+" Your search key is->"+searchKey);
                System.out.println("Thread will sleep now");
        
        Thread.sleep(3000);
        System.out.println("Value in Google Search Box = "+searchText.getAttribute("value") +" ::: Value given by input = "+searchKey);
        //verifying the value in google search box
        AssertJUnit.assertTrue(searchText.getAttribute("value").equalsIgnoreCase(searchKey));
}
}

一项研究,上面的例子。想象一下,当我们对 3 个输入组合执行此操作时,代码将变得多么复杂

现在,让我们使用以下方法对其进行参数化 TestNG

为此,您需要

  • 创建一个用于存储参数的 XML 文件
  • 在测试中,添加注解@Parameters

使用 Testng.Xml 进行参数注释

以下是完整的代码

测试级别 TestNG。XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestSuite" thread-count="3" >
<parameter name="author" value="Guru99" />
<parameter name="searchKey" value="India" />
<test name="testGuru">
<parameter name="searchKey" value="UK" />
<classes>
<class name="parameters.ParameterWithTestNGXML">
</class>
</classes>
</test>
</suite>

參數TestNGXML.java 文件

package parameters;

import org.testng.AssertJUnit;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class ParameterWithTestNGXML {
	String driverPath = "C:\\geckodriver.exe";
	WebDriver driver;
    @Test
    @Parameters({"author","searchKey"})
    public void testParameterWithXML( @Optional("Abc") String author,String searchKey) throws InterruptedException{

        System.setProperty("webdriver.gecko.driver", driverPath);
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("https://google.com");

        WebElement searchText = driver.findElement(By.name("q"));
        //Searching text in google text box
        searchText.sendKeys(searchKey);

        System.out.println("Welcome ->"+author+" Your search key is->"+searchKey);
        System.out.println("Thread will sleep now");
        Thread.sleep(3000);
        System.out.println("Value in Google Search Box = "+searchText.getAttribute("value") +" ::: Value given by input = "+searchKey);
        //verifying the value in google search box
        AssertJUnit.assertTrue(searchText.getAttribute("value").equalsIgnoreCase(searchKey));

}
}

运行脚本的说明,选择 XML 文件并作为 Test NG Suite 运行

右键单击 .xml 文件 -> 以...身份运行 -> 测试 套房 (註釋:套房)

參數TestNGXML.java 文件

现在,可以在两个级别定义参数

  1. 套件级别 – 内部的参数标签 TestNG XML 文件将是一个套件级参数。
  2. 测试级别——测试 XML 文件的标签将作为测试级别参数。

以下是使用套件级别参数的相同测试

參數TestNGXML.java 文件

注意: 如果套件级别和测试级别的参数名称相同,则测试级别参数将优先于套件级别。因此,在这种情况下,该测试级别内的所有类将共享覆盖的参数,而测试级别之外的其他类将共享套件级别参数。

參數TestNGXML.java 文件

故障排除

问题 #1 testng.xml 中的参数值不能转换为相应测试方法的参数,否则会引发错误。

考虑以下示例

故障排除

这里,“author”属性等于“Guru99”,它是一个字符串,并且在相应的测试方法中它需要一个整数值,所以我们会在这里得到一个异常。

问题 #2 您的@Parameters 在testing.xml中没有相应的值。

您可以通过添加来解决此情况 @选修的 注解 在测试方法中相应的参数中。

故障排除

问题 # 3: 您想使用 Testng.xml 测试同一参数的多个值

简单的答案是这不可能!您可以有多个不同的参数,但每个参数只能有一个值。这有助于防止将值硬编码到脚本中。这使得代码可重复使用。将其视为脚本的配置文件。如果您想为参数使用多个值,请使用 DataProviders

数据提供者 TestNG

数据提供者 TestNG 是用户需要传递复杂参数时使用的方法。复杂参数需要从 Java 比如复杂对象,来自属性文件或数据库的对象可以通过数据提供者方法传递。该方法由@DataProvider注释,并返回一个对象数组。

使用 Dataprovider 的参数

@Parameters 注释很容易,但要使用多组数据进行测试,我们需要使用数据提供程序。

为了使用我们的测试框架填写数千个网络表单,我们需要一种不同的方法,它可以在单个执行流中为我们提供非常大的数据集。

这种数据驱动的概念是通过 @DataProvider 注释 TestNG.

使用 Dataprovider 的参数

它只有一个 属性‘名称’。如果不指定 name 属性,则 DataProvider 的名称将与相应的方法名称相同。

数据提供者返回 二维 JAVA 对象 到测试方法,测试方法会在一个M*N类型的对象数组中调用M次。比如DataProvider返回一个2*3类型的对象数组,那么对应的testcase就会被调用2次,每次传入3个参数。

使用 Dataprovider 的参数

完整示例

使用 Dataprovider 的参数

package parameters;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByDataprovider {
    WebDriver driver;
    String driverPath = "C:\\geckodriver.exe";

    @BeforeTest
    public void setup(){
        //Create firefox driver object
         System.setProperty("webdriver.gecko.driver", driverPath);
         driver = new FirefoxDriver();
         driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
         driver.get("https://google.com");
    }
 
    /** Test case to verify google search box
     * @param author
     * @param searchKey
     * @throws InterruptedException
     */

    @Test(dataProvider="SearchProvider")
    public void testMethod(String author,String searchKey) throws InterruptedException{
    {
        WebElement searchText = driver.findElement(By.name("q"));
        //search value in google searchbox
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->"+author+" Your search key is->"+searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getAttribute("value");
        System.out.println(testValue +"::::"+searchKey);
        searchText.clear();
        //Verify if the value in google search box is correct
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }
    }
    /**
     * @return Object[][] where first column contains 'author'
     * and second column contains 'searchKey'
     */

    @DataProvider(name="SearchProvider")
    public Object[][] getDataFromDataprovider(){
    return new Object[][] 
    	{
            { "Guru99", "India" },
            { "Krishna", "UK" },
            { "Bhupesh", "USA" }
        };

    }

}

从不同的类调用 DataProvider

默认情况下,DataProvider 位于测试方法所在的同一类或其基类中。要将其放在其他类中,我们需要将数据提供程序方法设为静态,并在测试方法中添加一个属性 数据提供者类 in @测试 注解。

从不同的类调用 DataProvider

代码示例

从不同的类调用 DataProvider

测试类ParameterDataproviderWithClassLevel.java

package parameters;

import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class ParameterDataproviderWithClassLevel {
    WebDriver driver;
    String driverPath = "C:\\geckodriver.exe";
    
 	@BeforeTest
    public void setup(){
 		System.setProperty("webdriver.gecko.driver", driverPath);
		driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("https://google.com");
    }
   
    @Test(dataProvider="SearchProvider",dataProviderClass=DataproviderClass.class)
    public void testMethod(String author,String searchKey) throws InterruptedException{
        
        WebElement searchText = driver.findElement(By.name("q"));
        //Search text in google text box
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->"+author+" Your search key is->"+searchKey);
        Thread.sleep(3000);
        //get text from search box
        String testValue = searchText.getAttribute("value");
        System.out.println(testValue +"::::"+searchKey);
        searchText.clear();
        //verify if search box has correct value
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
   }
}

数据提供者类.java

package parameters;

import org.testng.annotations.DataProvider;
public class DataproviderClass {
        @DataProvider(name="SearchProvider")
        public static Object[][] getDataFromDataprovider(){
            return new Object[][] {
                { "Guru99", "India" },
                { "Krishna", "UK" },
                { "Bhupesh", "USA" }
            };  
}}

Dataprovider 中的参数类型

DataProvider 方法支持两种类型的参数。

付款方式–如果 SAME DataProvider 应该根据不同的测试方法表现出不同的行为,并使用 Method 参数。

DataProvider 中的参数类型

在以下示例中,

  • 我们检查方法名称是否是 testMethodA。
  • 如果是,返回一组值
  • 否则返回另一组值
package parameters;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByMethodInDataprovider{

    WebDriver driver;
    String driverPath = "C:\\geckodriver.exe";
     
    @BeforeTest
    public void setup(){
    	System.setProperty("webdriver.gecko.driver", driverPath);
    	driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("https://google.com");
    }

    @Test(dataProvider="SearchProvider")
    public void testMethodA(String author,String searchKey) throws InterruptedException{
        
    	WebElement searchText = driver.findElement(By.name("q"));
        //Search text in search box
        searchText.sendKeys(searchKey);
        //Print author and search string
        System.out.println("Welcome ->"+author+" Your search key is->"+searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getAttribute("value");
        System.out.println(testValue +"::::"+searchKey);
        searchText.clear();
        //Verify if google text box is showing correct value
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }
      
    @Test(dataProvider="SearchProvider")
    public void testMethodB(String searchKey) throws InterruptedException{
        {
        	WebElement searchText = driver.findElement(By.name("q"));
            //Search text in search box
            searchText.sendKeys(searchKey);
            //Print only search string
            System.out.println("Welcome ->Unknown user Your search key is->"+searchKey);
            Thread.sleep(3000);
            String testValue = searchText.getAttribute("value");
            System.out.println(testValue +"::::"+searchKey);
            searchText.clear();
            //Verify if google text box is showing correct value
            Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
        }
    }    
    /**
     * Here DataProvider returning value on the basis of test method name
     * @param m
     * @return
     **/

    @DataProvider(name="SearchProvider")
    public Object[][] getDataFromDataprovider(Method m){
        if(m.getName().equalsIgnoreCase("testMethodA")){
        return new Object[][] {
                { "Guru99", "India" },
                { "Krishna", "UK" },
                { "Bhupesh", "USA" }
            };}
        else{
        return new Object[][] {
                { "Canada" },
                { "Russia" },
                { "Japan" }
            };}       
    }
}

输出如下

DataProvider 中的参数类型

测试上下文– 它可以用来根据组为测试用例创建不同的参数。

在现实生活中,您可以使用 ITestContext 根据测试方法、主机和测试配置来改变参数值。

DataProvider 中的参数类型

在下面的代码示例中

  • 我们有 A 和 B 两个组
  • 每种测试方法都分配到一个组
  • 如果组的值为 A,则返回特定数据集
  • 如果组的值为 B,则返回另一个数据集
package parameters;

import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByITestContextInDataprovider {
	WebDriver driver;
	String driverPath = "C:\\geckodriver.exe";
	@BeforeTest(groups={"A","B"})
	public void setup(){
		System.setProperty("webdriver.gecko.driver", driverPath);
		  	driver = new FirefoxDriver();
			driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
			driver.get("https://google.com");
	}
	
	@Test(dataProvider="SearchProvider",groups="A")
	public void testMethodA(String author,String searchKey) throws InterruptedException{
		{
		  //search google textbox
			WebElement searchText = driver.findElement(By.name("q"));
			//search a value on it
			searchText.sendKeys(searchKey);
			System.out.println("Welcome ->"+author+" Your search key is->"+searchKey);
			Thread.sleep(3000);
			String testValue = searchText.getAttribute("value");
			System.out.println(testValue +"::::"+searchKey);
			searchText.clear();
			//verify correct value in searchbox
			Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
	}
	}
	
	@Test(dataProvider="SearchProvider",groups="B")
	public void testMethodB(String searchKey) throws InterruptedException{
		{
		  //find google search box
			WebElement searchText = driver.findElement(By.name("q"));
			//search a value on it
			searchText.sendKeys(searchKey);
			System.out.println("Welcome ->Unknown user Your search key is->"+searchKey);
			Thread.sleep(3000);
			String testValue = searchText.getAttribute("value");
			System.out.println(testValue +"::::"+searchKey);
			searchText.clear();
			//verify correct value in searchbox
			Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
	}
	}
	
	/**
	 * Here the DAtaProvider will provide Object array on the basis on ITestContext
	 * @param c
	 * @return
	 */
	@DataProvider(name="SearchProvider")
	public Object[][] getDataFromDataprovider(ITestContext c){
	Object[][] groupArray = null;
		for (String group : c.getIncludedGroups()) {
		if(group.equalsIgnoreCase("A")){
			groupArray = new Object[][] { 
					{ "Guru99", "India" }, 
					{ "Krishna", "UK" }, 
					{ "Bhupesh", "USA" } 
				};
		break;	
		}
			else if(group.equalsIgnoreCase("B"))
			{
			groupArray = new Object[][] { 
						{  "Canada" }, 
						{  "Russia" }, 
						{  "Japan" } 
					};
			}
		break;
	}
	return groupArray;		
	}
}

注意:如果您直接运行 testng 类,它将首先调用 dataprovider,由于组不可用,因此无法获取组信息。但是,如果您通过 testng.xml 调用此类,它将通过 ITestContext 获取组信息。使用以下 XML 调用测试

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="test-parameter">

  <test name="example1">

    <groups>
        <run>
            <include name="A" />
        </run>
    </groups>

    <classes>
       <class
        name="parameters.ParameterByITestContextInDataprovider" />
    </classes>

  </test>


  <test name="example2">

    <groups>
        <run>
            <include name="B" />
        </run>
    </groups>

    <classes>
       <class
        name="parameters.ParameterByITestContextInDataprovider" />
    </classes>

  </test>

</suite>

总结

  • 参数化 需要创建 数据驱动测试.
  • TestNG 支持两种参数化,使用 @参数+TestNG。XML 和使用@DataProvider
  • In @参数+TestNG。XML 参数可以放在套件级别和测试级别。如果

    两个地方声明了相同的参数名称;测试级别参数将优先于适合级别参数。

  • 使用@Parameter+TestNG.xml 一次只能设置一个值,但 @DataProvider 返回 一个二维对象数组.
  • 如果 DataProvider 存在于不同的类中,那么测试方法所在的类,数据提供者 应该 静态方法.
  • 支持两个参数 数据提供者 旨在 付款方式ITestContext。