数据驱动测试是自动化测试中一种重要的设计模式,这种设计模式可以将测试数据和测试代码分开,实现数据与代码解耦,与此同时还能够实现一次任务中使用不同的数据来执行执行相同的测试脚本,因此它会使得我们的代码层次结构清晰,容易维护,并且大大降低了代码量
数据驱动是自动化测试中非常常见的一种设计模式,应用的场景非常多,无论是在Web自动化还是在接口自动化、单元测试,亦或是在数据分析应用领域的测试上都会得到非常广泛的使用,常见的比如Web自动化的登录功能、一些录入类的功能,再比如接口入参、单元测试的入参,甚至在数据类应用的大量数据输入及结果比较上
[数据驱动Data@Parameters]
测试代码
package com.davieyang.application;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;public class ParameterDemo {@Parameters({"newParameter"})@Testpublic void testCase(String para){System.out.println("参数值为" + para);}
}
配置执行
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<!--Parameters-->
<suite name="All Test Suite"><parameter name="newParameter" value="Niubility"/><test verbose="2" preserve-order="true" name="Demo"><classes><class name="com.davieyang.application.ParameterDemo"><methods><include name="testCase"/></methods></class></classes></test>
</suite>
[数据驱动Data@DataProvider]
TestNG单元测试框架提供了@DataProvider注解,利用这个注解可以很方便实现数据驱动,执行单元测试
package com.davieyang.application;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;public class DataDrivenDemo {@DataProvider(name = "data")public Object[][] dataProvider(){return new Object[][]{new Object[]{"账号为空", "密码正确", "账号不能为空"}, new Object[]{"账号正确", "密码为空", "密码不能为空"},new Object[]{"账号正确", "密码正确", "登陆成功"}};}@Test(dataProvider = "data")public void testCase(String username, String password, String prompt){System.out.println("If input:" + username + " 、" + password + ",提示" + prompt);}
}
[数据驱动DP&CSV]
package testNGWithDataDriven;import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;public class TestNGCsvDriven {public WebDriver driver;String baseUrl = "http://www.sogou.com";//使用注解DataProvider将数据集合命名为“csvTestData”@DataProvider(name = "csvTestData")public static Object[][]words() throws IOException{//调用类中的静态方法getTestData,获取CSV文件的测试数据return getTestData("F:\\TestNGWithDataDriven\\dataDriven\\src\\test\\java\\testData\\testData.csv");}@BeforeMethodpublic void beforeMethod(){driver = new ChromeDriver();}@Test(dataProvider = "csvTestData")public void testSearch(String searchWord1, String searchWord2, String searchResult){driver.get(baseUrl+"/");driver.findElement(By.id("query")).sendKeys(searchWord1+" "+searchWord2);driver.findElement(By.id("stb")).click();Assert.assertTrue(driver.getPageSource().contains(searchResult));}@AfterMethodpublic void afterMethod(){driver.quit();}//读取CSV文件的静态方法,使用CSV文件的绝对文件路径作为函数参数public static Object[][] getTestData(String fileName) throws IOException{List<Object[]> records = new ArrayList<Object[]>();String record;//设定UTF-8字符集,使用带缓冲区的字符输入流BufferedRead读取文件内容BufferedReader file = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "GBK"));//忽略读取CSV文件的标题行file.readLine();/** 遍历读取文件中除去第一行外的其他所有内容* 并存储在名人records的ArrayList中* 每一个records中存储的对象为一个String数组*/while ((record=file.readLine())!=null){String fields[]=record.split(",");records.add(fields);}//关闭文件对象file.close();//定义函数返值, 即Object[][]//将存储测试数据的list转换为一个Object的二维数组Object[][] results = new Object[records.size()][];//设置二维数组每行的值,每行是一个Object对象for (int i = 0; i<records.size(); i++){results[i] = records.get(i);}return results;}
}
[数据驱动DP&MySql]
package testNGWithDataDriven;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.sql.*;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;public class TestNGDBDriven {public WebDriver driver;String baseUrl = "http://www.sogou.com";@DataProvider(name="testdata")public static Object[][] words() throws IOException{return getTestData("testdata");}@Test(dataProvider = "testdata")public void testSearch(String searchWord1, String searchWord2, String searchResult){driver.get(baseUrl + "/");driver.findElement(By.id("query")).sendKeys(searchWord1+" "+searchWord2);driver.findElement(By.id("stb")).click();Assert.assertTrue(driver.getPageSource().contains(searchResult));}@BeforeMethodpublic void beforeMethod(){driver = new ChromeDriver();}@AfterMethodprivate void afterMethod(){driver.quit();}public static Object[][] getTestData(String tablename) throws IOException{//声明Mysql数据库的驱动String dbDriver = "com.mysql.cj.jdbc.Driver";String url = "jdbc:mysql://127.0.0.1:3306/testng?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";String user = "root";String password = "root";//声明存储测试数据的List对象List<Object[]> records = new ArrayList<Object[]>();try{//设定驱动Class.forName(dbDriver);Connection conn = DriverManager.getConnection(url,user,password);if (!conn.isClosed())System.out.println("连接数据库成功");//创建statement对象Statement statement = conn.createStatement();//拼接sql语句String sql = String.format("Select * from %s", tablename);//声明结果集对象rs,用于存储执行sql语句返回的数据结果集ResultSet rs = statement.executeQuery(sql);//声明一个ResultSetMetaData对象ResultSetMetaData rsMetaData = rs.getMetaData();//调用ResultSetMetaData对象的getColumnCount方法获取数据行的列数int cols = rsMetaData.getColumnCount();/**使用next方法遍历数据结果集中的所有数据行*/while (rs.next()){//声明一个字符串型数组,数组大小使用数据行的列个数进行声明String fields[] = new String[cols];int col = 0;//遍历所有数据行中的所有数据,并存储在字符串数组中for (int colIdx = 0; colIdx<cols; colIdx++){fields[col] = rs.getString(colIdx+1);col++;}//将每一行的数据存储到字符串数组后,存储到records中records.add(fields);//输出数据行中的前三列内容,用于验证数据库内容是否正确读取System.out.println(rs.getString(1)+" "+rs.getString(2)+" "+rs.getString(3));}//关闭数据结果集对象rs.close();//关闭数据库连接conn.close();}catch (ClassNotFoundException e){System.out.println("未能找到Mysql的驱动类");e.printStackTrace();} catch (Exception e){e.printStackTrace();}//定义函数返回值,即Object[][]//将存储测试数据的list转换为一个Object的二维数组Object[][] results = new Object[records.size()][];//设置二维数组每行的值,每行是一个Object对象for (int i = 0; i<records.size(); i++){results[i] = records.get(i);}return results;}
}
[数据驱动DP&数组]
package testNGWithDataDriven;import java.util.concurrent.TimeUnit;
import org.testng.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;public class TestNGDriven {private static WebDriver driver;@DataProvider(name="searchWords")public static Object[][] words(){return new Object[][]{{"蝙蝠侠","主演","迈克尔"},{"超人","导演","唐纳"},{"生化危机","编剧","安德森"}};}@Test(dataProvider = "searchWords")public void test(String searchWord1, String searchWord2, String SearchResult){driver = new ChromeDriver();driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);driver.get("http://www.sogou.com");driver.findElement(By.id("query")).sendKeys(searchWord1+" "+searchWord2);driver.findElement(By.id("stb")).click();try{Thread.sleep(3000);}catch (InterruptedException e){e.printStackTrace();}Assert.assertTrue(driver.getPageSource().contains(SearchResult));driver.quit();}
}
[数据驱动DP&Excel]
package testNGWithDataDriven;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;public class TestNGExcelDriven {public WebDriver driver;String baseUrl = "http://www.sogou.com";@DataProvider(name="testData")public static Object[][] words() throws IOException{return getTestData("F:\\TestNGWithDataDriven\\dataDriven\\src\\test\\java\\testData", "testData.xlsx", "Sheet1");}@Test(dataProvider = "testData")public void testSearchExcel(String searchWord1, String searchWord2, String searchWord3, String searchResult){driver.get(baseUrl + "/");driver.findElement(By.id("query")).sendKeys(searchWord1+" "+searchWord2+" "+searchWord3);driver.findElement(By.id("stb")).click();Assert.assertTrue(driver.getPageSource().contains(searchResult));}@BeforeMethodpublic void beforeMethod(){driver = new ChromeDriver();}@AfterMethodprivate void afterMethod(){driver.quit();}public static Object[][] getTestData(String filePath, String fileName, String sheetName) throws IOException{File file = new File(filePath + "\\" + fileName);//创建FileInputStream对象用于读取Excel文件FileInputStream inputStream = new FileInputStream(file);//声明Workbook对象Workbook workbook = null;//获取文件名参数的扩展名,判断是.xlsx文件还是.xls文件String fileExtensionName = fileName.substring(fileName.indexOf("."));//如果是.xlsx,则用XSSFWorkbook对象进行实例化,如果是.xls则使用HSSFWorkbook对象进行实例化if (fileExtensionName.equals(".xlsx")){workbook = new XSSFWorkbook(inputStream);}else if (fileExtensionName.equals(".xls")) {workbook = new HSSFWorkbook(inputStream);}//通过sheetName参数生成Sheet对象Sheet sheet = workbook.getSheet(sheetName);//获取Excel数据文件Sheet1中数据的行数,getLastRowNum方法获取数据的最后一行行号//getFirstRowNum方法获取数据的第一行行号,相减之后算出数据的行数//Excel行和列都是从0开始int rowCount = sheet.getLastRowNum()-sheet.getFirstRowNum();//创建名为records的list对象来存储从Excel数据文件读取的数据List<Object[]> records = new ArrayList<Object[]>();//使用两个for循环遍历Excel数据文件除去第一行外所有数据//所以i从1开始,而不是从0开始for (int i = 1; i<rowCount+1; i++){Row row = sheet.getRow(i);//声明一个数组,用来存储Excel数据文件每行中的数据,数组的大小用getLastCellNum办法来进行动态声明,实现测试数据个数和数组大小相一致String fields[] = new String[row.getLastCellNum()];for (int j = 0; j<row.getLastCellNum();j++){//调用getCell和getStringCellValue方法获取Excel文件中的单元格数据fields[j] = row.getCell(j).getStringCellValue();}//将fields的数据兑现存储到records的list中records.add(fields);}//定义函数返回值,即Object[][]//将存储测试数据的list转换为一个Object的二维数组Object[][] results = new Object[records.size()][];//设置二维数组每行的值,每行是一个Object对象for (int i = 0; i<records.size(); i++){results[i] = records.get(i);}return results;}
}