创建软件时,总是希望它能以不同的方式处理不同的数据集。当涉及到测试同样的软件,不能用一组数据来测试它。我们需要参数化。
Selenium中的参数化
Selenium中的参数化是一个参数化测试脚本的过程,以便在运行时将多个数据传递给应用程序。通过参数化测试脚本实现的概念称为数据驱动测试 。
在本教程中,将了解-
- TestNG中的参数化类型
- 使用Testng.xml进行参数标注
- 故障排除
- 使用数据提供程序的参数
- 从不同的类调用DataProvider
- 数据提供程序中的参数类型
TestNG中的参数化类型
为了使参数化更清楚,将在Selenium Webdriver最流行的框架中介绍参数化选项- TestNG 。 确实有两种方式可以实现测试过程中的参数化
- 注解和测试XML。

- 数据提供程序下注解。


Testng.xml中的参数可以是套件级别或测试级别
DataProvider中的参数可以采用Method和ITestContext作为参数。
TestNG中的参数注解
TestNG中的参数标注是一种使用.xml文件将值作为参数传递给测试方法的方法。 @Parameters注解方法可用于任何具有 @Test 、 @Before 、 @After或 @Factory注解的方法 。
使用Testng.xml进行参数标注
如果确实想要处理复杂性&输入组合的数量较少,选择使用注解进行参数化。
测试场景
步骤1) 启动浏览器并转到google.com
步骤2) 输入搜索关键字

步骤3) 验证输入的值是否与我们的测试数据提供的值相同
步骤4) 重复2&3,直到输入所有数值
下面是一个示例,说明如何在没有参数的情况下执行此操作
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 = "itxiaonv";
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
<?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="itxiaonv" />
<parameter name="searchKey" value="India" />
<test name="testGuru">
<parameter name="searchKey" value="UK" />
<classes>
<class name="parameters.ParameterWithTestNGXML"></class>
</classes>
</test>
</suite>
ParameterWithTestNGXML.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文件并作为TestNG套件运行。右键单击.xml文件- >运行方式-> TestNG (注:套件)

现在,可以在两个级别定义参数
- 套件级别-TestNG XML文件的<Suite>标记内的参数将是套件级别参数。
- 测试级别–测试XML文件的<Test>标记内的参数将是测试级别参数。
下面是带有套件级别参数的相同测试

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

故障排除
第1 不能将testng.xml中的参数值类型转换为相应测试方法的参数,这将引发错误。
考虑以下示例

在相应的测试方法中,它需要一个整数值,所以我们在这里会得到一个异常。
第2 @参数在testing.xml中没有相应值 。
可以通过添加 @可选 注解 在测试方法中的相应参数中。

第3期 : 希望使用Testng.xml测试同一参数的多个值
答案很简单,这是做不到的!可以有多个不同的参数如果要为一个参数使用多个值,使用DataProviders
TestNG中的数据提供程序
TestNG中的数据提供程序 是用户需要传递复杂参数时使用的方法。需要从Java创建复杂参数,如复杂对象、来自PROPE的对象该方法由@DataProvider注释,并返回一个对象数组。
使用数据提供程序的参数
@Parameters注释很简单 ,但是要测试多组数据,我们需要使用数据提供程序。
要使用我们的测试框架填写数千个Web表单,我们需要一种不同的方法,可以在单个执行流程中提供非常大的数据集。 这种数据驱动的概念是通过以下方式实现的 @DataProvider TestNG中的注解。

它只有一个 属性“name” 。如果不指定name属性,则DataProvider的名称将与相应的方法名称相同。 数据提供程序返回 二维Java对象 对于测试方法和测试方法,将在M*N类型的对象数组中调用M次。例如,如果DataProvider返回2*3个对象的数组,则对应的测试用例将被调用2次,每次调用3个参数。

完整示例

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[][] {
{ "ITXiaonv", "India" },
{ "Krishna", "UK" },
{ "Bhupesh", "USA" }
};
}
}
从不同的类调用DataProvider
默认情况下,DataProvider驻留在测试方法所在的类或其基类中。要将其放入其他类中,我们需要将数据提供程序方法设置为静电,而在测试方法中,我们需要添加一个属性 dataProviderClass 在@Test注释里面 。

代码示例

TestClass 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));
}
}
DataproviderClass.java
package parameters;
import org.testng.annotations.DataProvider;
public class DataproviderClass {
@DataProvider(name="SearchProvider")
public static Object[][] getDataFromDataprovider() {
return new Object[][] {
{ "ITXiaonv", "India" },
{ "Krishna", "UK" },
{ "Bhupesh", "USA" }
};
}
}
数据提供程序中的参数类型
DataProvider方法支持两种类型的参数。
方法 -对于不同的测试方法,如果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" }
};
}
}
}
这是输出

ITestContext -它可以用于基于组为测试用例创建不同的参数。
在现实生活中,可以使用ITestContext根据测试方法、主机和测试配置来改变参数值。

在下面的代码示例中
- 我们有A组和B组两个组
- 每种测试方法都分配给一个组
- 如果groups的值为A,则返回特定的数据集
- 如果groups的值为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,后者无法获取组信息,因为组不可用。使用以下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支持两种参数化,使用 @Parameter+TestNG.xml 或者 @DataProvider
-
在 @Parameter+TestNG.xml 里面参数可以放在套件级别和测试级别。如果 两个地方声明了相同的参数名称;测试级别参数将优先于套件级别参数。
- 使用@Parameter+TestNG.xml一次只能设置一个值,但@DataProvider返回 对象的二维阵列 。
- 如果DataProvider出现在与测试方法驻留的类不同的类中, 数据提供程序 应该是 静态法 。
-
DataProvider支持两个参数方法和ITestContext。