数据提供者 & TestNG XML:参数化 Selenium(例子)
参数化于 Selenium
参数化于 Selenium 是参数化测试脚本的过程,以便在运行时将多个数据传递给应用程序。这是一种使用不同值自动多次运行测试用例的执行策略。通过参数化测试脚本实现的概念称为 数据驱动测试.
参数化类型 TestNG-
为了使参数化更加清晰,我们将介绍最流行的框架之一中的参数化选项 Selenium Webdriver – TestNG.
这里有 两种方式 通过它可以实现参数化 TestNG
Testng.xml 中的参数可以是套件或测试级别
DataProvider 中的参数可以以 Method 和 ITestContext 作为参数。
让我们详细研究一下——
参数注释 TestNG
参数注释 TestNG 是一种使用 .xml 文件将值作为参数传递给测试方法的方法。用户可能需要在运行时将值传递给测试方法。@Parameters 注释方法可用于任何具有 @Test、@Before、@After 或 @Factory 注释的方法。
使用Testng.xml进行参数注释
当您确实想要处理复杂性且输入组合数量较少时,请选择使用注释进行参数化。
让我们看看它是如何工作的
测试场景
步骤 1)启动浏览器并转到 Google.com
步骤2)输入搜索关键字
步骤 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
<?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 文件 -> 以...身份运行 -> 测试 套房 (註釋:套房)
现在,可以在两个级别定义参数
- 套件级别 – 内部的参数标签 TestNG XML 文件将是一个套件级参数。
- 测试级别——测试 XML 文件的标签将作为测试级别参数。
以下是使用套件级别参数的相同测试
注意: 如果套件级别和测试级别的参数名称相同,则测试级别参数将优先于套件级别。因此,在这种情况下,该测试级别内的所有类将共享覆盖的参数,而测试级别之外的其他类将共享套件级别参数。
故障排除
问题 #1 testng.xml 中的参数值不能转换为相应测试方法的参数,否则会引发错误。
考虑以下示例
这里,“author”属性等于“Guru99”,它是一个字符串,并且在相应的测试方法中它需要一个整数值,所以我们会在这里得到一个异常。
问题 #2 您的@Parameters 在testing.xml中没有相应的值。
您可以通过添加来解决此情况 @选修的 注解 在测试方法中相应的参数中。
问题 # 3: 您想使用 Testng.xml 测试同一参数的多个值
简单的答案是这不可能!您可以有多个不同的参数,但每个参数只能有一个值。这有助于防止将值硬编码到脚本中。这使得代码可重复使用。将其视为脚本的配置文件。如果您想为参数使用多个值,请使用 DataProviders
数据提供者 TestNG
数据提供者 TestNG 是用户需要传递复杂参数时使用的方法。复杂参数需要从 Java 比如复杂对象,来自属性文件或数据库的对象可以通过数据提供者方法传递。该方法由@DataProvider注释,并返回一个对象数组。
使用 Dataprovider 的参数
@Parameters 注释很容易,但要使用多组数据进行测试,我们需要使用数据提供程序。
为了使用我们的测试框架填写数千个网络表单,我们需要一种不同的方法,它可以在单个执行流中为我们提供非常大的数据集。
这种数据驱动的概念是通过 @DataProvider 注释 TestNG.
它只有一个 属性‘名称’。如果不指定 name 属性,则 DataProvider 的名称将与相应的方法名称相同。
数据提供者返回 二维 JAVA 对象 到测试方法,测试方法会在一个M*N类型的对象数组中调用M次。比如DataProvider返回一个2*3类型的对象数组,那么对应的testcase就会被调用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[][] { { "Guru99", "India" }, { "Krishna", "UK" }, { "Bhupesh", "USA" } }; } }
从不同的类调用 DataProvider
默认情况下,DataProvider 位于测试方法所在的同一类或其基类中。要将其放在其他类中,我们需要将数据提供程序方法设为静态,并在测试方法中添加一个属性 数据提供者类 in @测试 注解。
代码示例
测试类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 参数。
在以下示例中,
- 我们检查方法名称是否是 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 根据测试方法、主机和测试配置来改变参数值。
在下面的代码示例中
- 我们有 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。