UI自动化测试框架

文章目录

    • UI自动化基础
    • 什么是UI自动化测试框架
    • UI自动化测试框架的模式
      • 数据驱动测试框架
      • 关键字驱动测试框架
      • 行为驱动测试框架
    • UI自动化测试框架的作用
    • UI自动化测试框架的核心思想
    • UI自动化测试框架的步骤
    • UI自动化测试框架的构成
      • Utils
        • Log.java
        • ReadProperties.Java
      • core
        • BaseTest.java打开游览器
        • ElementFinder.java元素查找封装类
        • SeleniumScreenShot.java截屏封装类
        • WebDriverEngine.java游览器操作封装类
        • WebTestListener1.java 监听器1,监听所有测试用例执行后的执行结果
        • WebTestListener1.java 监听器2,监听所有失败测试用例截屏
      • demo-测试用例包
        • Front_Login1.java测试用例类
      • dataprovider-数据驱动包
        • ExcelDataProvider.java-读取excel
        • MysqlDataProvider.java-读取sql
        • TxtDataProvider.java
      • data-数据文件夹
        • user.txt-存放用户名和密码
      • conf-配置文件夹
        • config.properties
      • libs-导入jar包
      • log4j2.xml日志打印格式
      • 常见异常
    • UI自动化测试框架的进阶构成
      • utils包:实现测试过程中调用的工具类方法,例如:文件操作、mapObject、页面对象的操作方法
        • Log.java
        • ObjectMap.java
        • ReadProperties.java
      • appModules包主要用于实现复用的业务逻辑封装方法
        • Login_Action.java
        • AddMessage_Action.java
      • pageObjects包:用于实现被测试的页面对象
        • LoginPage.java
        • AddMessagePage.java
      • testCases 包 :具体的测试方法
        • LoginTest.java
        • AddMessageTest.java
      • dataprovider包:提供数据驱动的类,txt驱动,excel驱动,数据库的驱动
      • core:游览器启动、table元素读取
        • BaseTest.java
        • Table.java

UI自动化基础

http://t.csdnimg.cn/aCCZ5

什么是UI自动化测试框架

UI自动化测试框架是应用于自动化测试的程序框架,它提供了可重用的自动化测试模块,提供最基本的自动化测试功能(打开浏览器,输入文字,点击按钮),或提供自动化测试执行和管理功能的架构模块(例如,TestNG)。它是由一个或多个自动化测试基础模块、自动化测试管理模块、自动化测试统计模块等组成的工具集合。

UI自动化测试框架的模式

  • 数据驱动测试框架
  • 关键字驱动测试框架
  • 混合型测试框架(页面对象+数据驱动+关键字
    驱动)
  • 行为驱动测试框架-Cucumber

数据驱动测试框架

使用数组、文件或者数据库等方式作为测试过程输入的自动化测试框架,此框架可以将所有的测试数据在自动化测试执行的过程中进行自动加载,动态判断测试结果是否符合预期,并自动输出测试报告。

关键字驱动测试框架

被操作的元素对象、操作的方法和操作的数据值作为测试过程输入的自动化测试框架。(存在于UFT工具中)可以保存在数组、文件或数据库中。
例如:输入框,输入,内容name:username, sendKeys, admin

行为驱动测试框架

行为驱动开发是一种敏捷软件开发技术,Behavior
Driven Development。Cucumber是实现BDD开发模式的一种测
试框架,实现了自然语言来执行相关联的测试代码的需求。
https://cucumber.io/ http://repo1.maven.org/maven2/info/cukes/

Cucumber-core.jar 核心包
Cucumber-java.jar 通过 java 编写需要下载这个包
Cucumber-html.jar 生成结果为 html 文件需要下载这个包
Cucumber-testng.jar 使用testng执行测试并生成报告

UI自动化测试框架的作用

  1. 能够有效组织和管理测试用例
  2. 将基础的代码封装,降低测试脚本编写的复杂性和重复性
  3. 提高测试脚本维护和修改的效率
  4. 自动执行测试脚本,并自动发布测试报告,为持续集成的开发方式提供脚本支持
  5. 让不具备编程能力的测试工程师开展自动化测试工作

UI自动化测试框架的核心思想

将常用的脚本代码或者测试逻辑进行抽象和总结,然后将这些代码进行面向对象设计,将需要复用的代码封装到可公用的类方法中。通过调用公用的类方法,测试类中的脚本复杂度会被大大降低,让更多脚本能力不强的测试人员来实施自动化测试。

UI自动化测试框架的步骤

1.根据测试业务的手工测试用例,选出需要自动化的用例(例如:冒烟测试)
2.根据可自动化执行的测试用例,分析出测试框架需要模拟的手工操作和重复高的测试流程或逻辑
3.将重复高的测试流程在代码中实现,并进行封装
4.根据业务的类型和本身的技术能力选择数据驱动测试、关键字驱动测试框架、混合型框架还是行为测试框架
5.确定框架类型后,将框架中的常用的浏览器选择、测试数据处理、文件操作、数据库操作、页面元素的原始操作、日志和报告等功能进行方法的封装实现
6.对框架代码进行集成测试和系统测试,采用PO模式和TestNG框架编写测试脚本,使用框架进行自动化测试,验证框架的功能是否可以满足自动化测试的需求。
7.编写自动化测试框架的常用API,以供他人参阅
8.在测试组中内部进行培训和推广
9.不断收集测试过程中的框架使用问题和反馈意见,不断增加和优化自动化框架的功能,不断增强框架中复杂操作的封装效果,尽量降低测试脚本的编写复杂性
10.定期评估测试框架的使用效果,评估自动化测试的投入和产出比,再逐步推广自动化框架的应用范围

UI自动化测试框架的构成

  • utils包:实现测试过程中调用的工具类方法,
  • core包主要用于实现复用的业务逻辑封装方法
  • demo包 :具体的测试用例方法
  • dataprovider包:提供数据驱动的类,txt驱动,excel驱动,数据库的驱动
    在这里插入图片描述

Utils

Log.java
  • 共有8个级别,按照从低到高为:All<Trace < Debug < Info < Warn < Error < Fatal <Off
    在这里插入图片描述

  • <PatternLayout pattern="[%-5p] %d %c %M - %m%n" />

    • %-5p表 示日志的级别,输出优先级,即ALL、TRACE,DEBUG,INFO,WARN,ERROR,FATAL、OFF【从低级别到高级别】
    • %d 打印日志的年月日时分毫秒信息
    • %c 打印类的名称
    • %M 输出发出日志请求的方法名
    • %m 打印具体的日志信息
    • %n 输出一个回车换行符
package com.webtest.utils;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log {
	static Logger logger = LogManager.getLogger();

	public static void startTestCase() {
		logger.info("----------------------");

	}

	public static void endTestCase() {
		logger.info("----------------------");

	}

	public static void fatal(String msg) {
		logger.fatal(msg);
	}

	public static void error(String msg) {
		logger.error(msg);
	}

	public static void warn(String msg) {
		logger.warn(msg);
	}

	public static void info(String msg) {
		logger.info(msg);
	}

	public static void debug(String msg) {
		logger.debug(msg);
	}
	
	public static void trace(String msg) {
		logger.trace(msg);
	}
}

ReadProperties.Java

读取文件属性

package com.webtest.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.testng.annotations.Test;

public class ReadProperties {

	public static final String filePath="conf/config.properties";
	

	public static String getPropertyValue(String key) throws IOException {
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream(filePath);
		prop.load(fis);
		fis.close();
		return prop.getProperty(key);
		
	}
}

core

BaseTest.java打开游览器
package com.webtest.core;


import java.io.IOException;

import java.time.Duration;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.ITestContext;
import org.testng.TestRunner;

import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeSuite;


import com.webtest.utils.Log;
import com.webtest.utils.ReadProperties;

public class BaseTest {

	public  WebDriverEngine webtest;
	private WebDriver driver;
	public String driverType;

	
	

	private WebDriver newWebDriver(String driverType) throws IOException {
		WebDriver driver = null;
	 if (driverType.equalsIgnoreCase("firefox")) {
		    String firefox_driver =ReadProperties.getPropertyValue("gecko_driver");
			String firefox_path = ReadProperties.getPropertyValue("firefox_path");
			System.setProperty("webdriver.gecko.driver", firefox_driver);
			System.setProperty("webdriver.firefox.bin", firefox_path);
			driver = new FirefoxDriver();
	
			Log.info("Using Firefox");
		}  else if (driverType.equalsIgnoreCase("chrome")) {
			String chrome_path = ReadProperties.getPropertyValue("chrome_path");
			System.setProperty("webdriver.chrome.driver",chrome_path);
			driver = new ChromeDriver();
			Log.info("Using Chrome");
			
		}else{
			return null;
		}

		
		return driver;

	
	}


	/**
	 * 
	 *打开浏览器
	 * 
	 */


	@BeforeClass
	public void doBeforeClass() throws Exception {

		driverType=ReadProperties.getPropertyValue("driverType");
		driver = this.newWebDriver(driverType);
		driver.manage().window().maximize();
		driver.manage().timeouts()
		.implicitlyWait(Duration.ofSeconds(5));
		Log.info(driverType);
		webtest = new WebDriverEngine(driver);
	
	
	
	}


//	@AfterClass
	public void doAfterMethod() {
		if(this.driver != null){
			this.driver.quit();
			}
		Log.info("Quitted Browser");
	}
	


	
	
	public WebDriver getDriver() {
        return driver;
    }

//	@BeforeSuite(description = "添加监听器")
	public void addListener(ITestContext context) {
		System.out.println("添加监听器");
		TestRunner runner =(TestRunner)context;
		runner.addListener(new WebTestListener1());
		runner.addListener(new WebTestListener2());
		
	}

	

}

ElementFinder.java元素查找封装类
package com.webtest.core;


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

import com.webtest.utils.Log;

public class ElementFinder {
	
	WebDriver driver;
	public  ElementFinder(WebDriver driver)
	{
		this.driver=driver;
	}
	

	
	public WebElement findElement(String target) {
		WebElement element = null;

		try {
			element = findElementByPrefix(target);
		} catch (Exception e) {

			Log.info(e.toString());
		}
		return element;

	}
	
	public WebElement findElementByPrefix(String locator)
	{
		String target=locator.trim();
		if(target.startsWith("id="))
		{
			locator = locator.substring("id=".length());
			return driver.findElement(By.id(locator));
		}else if(target.startsWith("class="))
		{
			locator = locator.substring("class=".length());
			return driver.findElement(By.className(locator));
		}else if(target.startsWith("name="))
		{
			locator = locator.substring("name=".length());
			return driver.findElement(By.name(locator));
		}else if(target.startsWith("link="))
		{
			locator = locator.substring("link=".length());
	
			return driver.findElement(By.linkText(locator));
		}else if(target.startsWith("partLink="))
		{
			locator = locator.substring("partLink=".length());
		
			return driver.findElement(By.partialLinkText(locator));
		}
		
		
		
		
		else if(target.startsWith("css="))
		{
			locator = locator.substring("css=".length());
			return driver.findElement(By.cssSelector(locator));
		}else if(target.startsWith("xpath="))
		{
			locator = locator.substring("xpath=".length());
			return driver.findElement(By.xpath(locator));
		}else if(target.startsWith("tag="))
		{
			locator = locator.substring("tag=".length());
			return driver.findElement(By.tagName(locator));
		}
		else
		{
			Log.info(locator+"can't find element by prefix.");
			return null;
		}
	}
	
}

SeleniumScreenShot.java截屏封装类
package com.webtest.core;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;

import com.google.common.io.Files;
import com.webtest.utils.Log;

public class SeleniumScreenShot {
    public WebDriver driver;
 
    public SeleniumScreenShot(WebDriver driver) {
        this.driver = driver;
    }
   
    public void screenShot() {
    	
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
		String nowDateTime = sdf.format(new Date());

		File s_file = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
		try {
			Files.copy(s_file, new File("D:\\demo\\" + nowDateTime + ".jpg"));
		} catch (IOException e) {
			Log.info("bad dir");		}
	
	}

}
WebDriverEngine.java游览器操作封装类
package com.webtest.core;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.Select;
import org.testng.Assert;
import org.testng.annotations.Test;

import com.webtest.utils.Log;
import com.webtest.utils.ReadProperties;

public class WebDriverEngine {

	WebDriver driver = null;
	ElementFinder finder = null;
	Actions action  =null;

	public WebDriverEngine(WebDriver driver) {
		
		this.driver = driver;
	
		finder = new ElementFinder(driver);
		action = new Actions(driver);
	}
	public String[] getAllWindowTitles() {
		// TODO Auto-generated method stub
	    String current = driver.getWindowHandle();

	    List<String> attributes = new ArrayList<String>();
	    for (String handle : driver.getWindowHandles()) {
	      driver.switchTo().window(handle);
	      attributes.add(driver.getTitle());
	    }

	    driver.switchTo().window(current);

	    return attributes.toArray(new String[attributes.size()]);
	}



	public void enterFrame(String frameID) {
		this.pause(3000);
		driver.switchTo().frame(frameID);
		Log.info("Entered iframe " + frameID);
	}
	public void enterFrame(int frameID) {
		this.pause(3000);
		driver.switchTo().frame(frameID);
		Log.info("Entered iframe " + frameID);
	}
	
	public void enterFrameLocator(String locator) {
		WebElement element = finder.findElement(locator);
		this.pause(3000);
		driver.switchTo().frame(element);
		Log.info("Entered iframe " + element);
	}


	public void leaveFrame() {
		driver.switchTo().defaultContent();
		Log.info("Left the iframe");
	}

	public void open(String url) {

		try {
			driver.get(ReadProperties.getPropertyValue("base_url")+url);
			pause(5000);
		} catch (Exception e) {
			e.printStackTrace();

		}
		Log.info("Opened url " + url);
	}

	public String getTitle() {
		return driver.getTitle();
	}

	private void pause(int time) {
		if (time <= 0) {
			return;
		}
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public boolean isTextPresent(String pattern) {

		String text = driver.getPageSource();
		text = text.trim();
		if (text.contains(pattern)) {
			return true;
		}
		return false;
	}
	public void enter() {
		action.sendKeys(Keys.ENTER);
	}

	public void typeAndClear(String locator, String value) {
		WebElement element = finder.findElement(locator);
		if (element != null) {
			element.clear();
			element.sendKeys(value);

		}
	}

	public void type(String locator, String value) {
		WebElement element = finder.findElement(locator);
		if (element != null) {
			element.sendKeys(value);
		}
	}

	public boolean isChecked(String locator) {
		WebElement element = finder.findElement(locator);
		return element.isSelected();
	}

	public void click(String locator) {

		WebElement element = finder.findElement(locator);
		if (element != null) {
			element.click();
			this.pause(3000);
		
		}
	}

	public void clear(String locator) {

		WebElement element = finder.findElement(locator);
		if (element != null) {
			element.clear();
			
		
		}
	}

	
	public void clickLonger(String locator) {

		WebElement element = finder.findElement(locator);
		if (element != null) {
			runJs("window.scrollTo(0," + element.getLocation().x + ")");
			element.click();
			this.pause(3000);
		}
	}

	public void doubleClick(String locator) throws InterruptedException {
		WebElement element = finder.findElement(locator);
	
		action.doubleClick(element).build().perform();
	}
	public void actionClick() {
		action.click().perform();
	}

	public boolean isDisplayed(String locator) {

		WebElement element = finder.findElement(locator);
		if (element != null) {
			return element.isDisplayed();
		}
		return false;
	}

	public String getText(String locator) {

		return finder.findElement(locator).getText().trim();
	}

	public boolean isElementPresent(String locator) {

		WebElement element = null;
		try {
			element = finder.findElement(locator);
		} catch (Exception e) {

			Log.info(e.getMessage());
		}
		if (element != null) {
			return true;
		}
		{
			return false;
		}
	}

	public String getValue(String locator) {

		return finder.findElement(locator).getAttribute("value");
	}

	public String getUrl() {
		return driver.getCurrentUrl();
	}

	public void goBack() {
		driver.navigate().back();
	}

	public void goForward() {

		driver.navigate().forward();
	}

	public Alert getAlert() {
		Alert alert = driver.switchTo().alert();
		return alert;
	}
	public String getAlertTest() {

		return getAlert().getText();
	}

	public void alertAccept() {

		getAlert().accept();
		}

	public Select getSelect(String locator) {
		Select inputSelect = new Select(finder.findElement(locator));
		return inputSelect;
	}

	public void selectByValue(String locator, String value) {
		getSelect(locator).selectByValue(value);
		this.pause(5000);
	}

	public void selectByVisibleText(String locator, String value) {
		getSelect(locator).selectByVisibleText(value);
	}

	public void selectByIndex(String locator, int index) {
		getSelect(locator).selectByIndex(index);
	}

	

	public String getHtmlSource() {

		return driver.getPageSource();
	}

	public void runJs(String js) {
		JavascriptExecutor j = (JavascriptExecutor) driver;
		j.executeScript(js);
	}


	public void mouseToElement(String locator) throws InterruptedException {
		action.moveToElement(finder.findElement(locator)).perform();
	}

	public void mouseToElementandClick(String locator) throws InterruptedException {
		action.moveToElement(finder.findElement(locator)).click().perform();
	}
	public void switchWidow(int i){
	    List<String> windows = new ArrayList<String>();
	    for (String handle : driver.getWindowHandles()) {
	    
	    	windows.add(handle);
	    }
	    driver.switchTo().window(windows.get(i));
	}

	public void rightClickMouse(String locator) throws InterruptedException {
		action.contextClick(finder.findElement(locator)).perform();
		}

	public void tapClick(){
	
		action.sendKeys(Keys.TAB).perform();;
	}
	
	public void downClick(){
		
		action.sendKeys(Keys.DOWN).perform();;
	}
	
	public void tapType(String content){
		
			action.sendKeys(content).perform();
		}
	
	public void getWindow(int i){
		List<String> windows = new ArrayList<String>();
		for (String handle : driver.getWindowHandles())
		{
			
			windows.add(handle);
		}
		driver.switchTo().window(windows.get(i));
	}



	
	
	
}

WebTestListener1.java 监听器1,监听所有测试用例执行后的执行结果
package com.webtest.core;

import java.io.IOException;
import java.util.List;

import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;

public class WebTestListener1 extends TestListenerAdapter {
	
	
	@Override
	public void onFinish(ITestContext testContext) {
		// TODO Auto-generated method stub
//		super.onFinish(testContext);
//		打印出所有的测试用例数目
		ITestNGMethod[] methods=this.getAllTestMethods();
		System.out.println("一共执行了:"+methods.length);
		
//		成功的/失败的测试用例名称和数目
		List<ITestResult> failList=this.getFailedTests();
		int len=failList.size();
		System.out.println("失败的测试用例:"+len);
		for(int i=0;i<len;i++) {
			ITestResult tr=failList.get(i);
			System.out.println(tr.getInstanceName()+":"+tr.getName()+"失败了");
			
		}
	}
}

WebTestListener1.java 监听器2,监听所有失败测试用例截屏
package com.webtest.core;

import java.io.IOException;
import java.util.List;

import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
/**
 * 失败的测试用例,进行截屏
 */
public class WebTestListener2 extends TestListenerAdapter {

	@Override
	public void onTestFailure(ITestResult tr) {

//		失败的测试用例截屏
		BaseTest tb = (BaseTest) tr.getInstance();
		SeleniumScreenShot screenShot = new SeleniumScreenShot(tb.getDriver());

		screenShot.screenShot();
		System.out.println("onTestFailure:" + tr.getInstanceName() + ":" + tr.getName() + "失败了");

	}

}

demo-测试用例包

Front_Login1.java测试用例类
package com.webtest.demo;

import static org.testng.Assert.assertTrue;

import org.testng.annotations.Test;

import com.webtest.core.BaseTest;

public class Front_Login1  extends BaseTest {

	@Test
	public void test_login_success() {
		webtest.open("/");
		webtest.click("link=登录");
		webtest.type("name=username","qingdao01");
		webtest.type("name=password","123456");
		webtest.click("xpath=//input[@value='马上登录']");
		assertTrue(webtest.isDisplayed("link=退出"));

	}
}

dataprovider-数据驱动包

ExcelDataProvider.java-读取excel
package com.webtest.dataprovider;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


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.testng.annotations.DataProvider;
import org.testng.annotations.Test;


public class ExcelDataProvider {



	public Object[][] getTestDataByExcel(String fileName, String sheetName)
			throws IOException {
		File file = new File(fileName);
		FileInputStream inputstream = new FileInputStream(file);
		Workbook wbook = null;
		String fileExtensionName = fileName.substring(fileName.indexOf("."));
		System.out.println(fileExtensionName);
		if (fileExtensionName.equals(".xlsx")) {
			wbook = new XSSFWorkbook(inputstream);
		
		} else if (fileExtensionName.equals(".xls")) {
			wbook = new HSSFWorkbook(inputstream);
		}
		Sheet sheet = wbook.getSheet(sheetName);
		
		int rowCount = sheet.getLastRowNum() - sheet.getFirstRowNum();
	
		List<Object[]> records = new ArrayList<Object[]>();
	
		for (int i = 1; i < rowCount + 1; i++) {
			Row row = sheet.getRow(i);
			String fields[] = new String[row.getLastCellNum()];
			for (int j = 0; j < row.getLastCellNum(); j++) {
			
				fields[j] = row.getCell(j).getStringCellValue();
			}
			records.add(fields);
		}
		Object[][] results = new Object[records.size()][];
		for (int i = 0; i < records.size(); i++) {
			results[i] = records.get(i);
		}
		return results;
	}
	

}

MysqlDataProvider.java-读取sql
package com.webtest.dataprovider;

import java.io.IOException;
import java.sql.*;

import java.util.ArrayList;
import java.util.List;

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

public class MysqlDataProvider {
	

	
	public  Object[][] getTestDataByMysql(String sql) {
		String url = "jdbc:mysql://127.0.0.1:3306/mymovie";
		List<Object[]> records = new ArrayList<Object[]>();

		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection conn = DriverManager
					.getConnection(url, "root", "123456");
			if (!conn.isClosed()) {
				System.out.println("连接数据库");
			}
		
			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery(sql);
			ResultSetMetaData rsMetaData = rs.getMetaData();
			int cols = rsMetaData.getColumnCount();
			System.out.println(cols);
			while (rs.next()) {
				String fields[] = new String[cols];

				int col=0;
				for (int i = 0; i < cols; i++) {
					fields[col] = rs.getString(i+1);
					col++;
				}
				records.add(fields);
			
			}
			rs.close();
			conn.close();

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Object[][] results = new Object[records.size()][];
		for (int i = 0; i < records.size(); i++) {
			results[i] = records.get(i);
		}
	
		return results;
	}


}

TxtDataProvider.java
package com.webtest.dataprovider;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

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

public class TxtDataProvider {
	
	
	public Object[][] getTxtUser(String fileName) throws IOException {
		
		List<String> dataList = new ArrayList<String>();
	
		File file = new File(fileName);
		FileInputStream fis = new FileInputStream(file);
		InputStreamReader isr= new InputStreamReader(fis);
		BufferedReader reader = new BufferedReader(isr);
		int cols=reader.readLine().split("\t").length;
		
		String readData;
		while((readData=reader.readLine())!=null) {
			dataList.add(readData);
		}
		
		Object [][] result = new Object[dataList.size()][cols];
		String [] arrays;
		for(int i=0;i<dataList.size();i++) {
			arrays=dataList.get(i).split("\t");
			for(int j=0;j<cols;j++)
				result[i][j]=arrays[j];
		}
		return result;
		
	}


	

}

data-数据文件夹

user.txt-存放用户名和密码
username	password
qingdao01	123456
qingdao02	123456

在这里插入图片描述

conf-配置文件夹

config.properties
gecko_driver=D:\\demo\\demo1\\geckodriver.exe
firefox_path=C:\\Program Files\\Mozilla Firefox\\firefox.exe
chrome_path=D:\\demo\\chromedriver.exe 
driverType=firefox
base_url=http://localhost:8032/mymovie
conf_root=conf/
data_root=data/
object_root=object/
host=localhost
port=4444
screen_name=D:\\edutest\\screenshot
ie_path=D:\\demo\\IEDriverServer.exe 
output_directory=test-output
enable_email=true
timeout = 3000
tomail=124434@qq.com,232324@qq.com,121213@qq.com

在这里插入图片描述

libs-导入jar包

在这里插入图片描述

log4j2.xml日志打印格式

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
	<Appenders>
	
		<Console name="Console" target="SYSTEM_ERR">
			<PatternLayout pattern="[%-5p] %d %c - %m%n" />
		</Console>
		<File name="File" fileName="dist/my.log">
			<PatternLayout pattern="[%-5p] %d %c - %m%n" />
		</File>
	</Appenders>
	<Loggers>
		<Root level="info">
			<AppenderRef ref="File" />
			<AppenderRef ref="Console" />
		</Root>
	</Loggers>
</Configuration>

在这里插入图片描述

常见异常

org.openqa.selenium.NoSuchElementException
  • 定位方式是不是写错了?
  • 是不是页面还未加载完?使用Thread.sleep(3000);//等待浏览器加载
  • 是不是存在多个窗口?使用switchTo().window(s) 尝试切换窗口
  • 是不是存在子页面?例如iframe中,使用switchTo(). frame(String nameOrId);进行切换
  • div嵌套太多,建议尝试用键盘鼠标事件action.clickAndHold().moveByOffset(x, y).release().perform();
  • 是不是页面太长,尝试向下移动滚动条

UI自动化测试框架的进阶构成

  • utils包:实现测试过程中调用的工具类方法,例如:文件操作、mapObject、页面对象的操作方法
  • appModules包主要用于实现复用的业务逻辑封装方法
  • pageObjects包:用于实现被测试的页面对象
  • testCases 包 :具体的测试方法
  • dataprovider包:提供数据驱动的类,txt驱动,excel驱动,数据库的驱动
  • 在这里插入图片描述

utils包:实现测试过程中调用的工具类方法,例如:文件操作、mapObject、页面对象的操作方法

Log.java
package com.edu.utils;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log {
	static Logger logger =LogManager.getLogger();
	


	public static void fatal(String msg) {
		logger.fatal(msg);
	}

	public static void error(String msg) {
		logger.error(msg);
	}

	public static void warn(String msg) {
		logger.warn(msg);
	}

	public static void info(String msg) {
		logger.info(msg);
	}

	public static void debug(String msg) {
		logger.debug(msg);
	}
}


ObjectMap.java
package com.edu.utils;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.openqa.selenium.By;
import org.testng.annotations.Test;

public class ObjectMap {

	Properties prop = null;

	public ObjectMap(String propFile) {
		prop = new Properties();
		FileInputStream in;
		try {
			in = new FileInputStream(propFile);
			prop.load(in);
			in.close();
		} catch (IOException e) {

			e.printStackTrace();
		}

	}


	public By getlocator(String ElementNameInProp) throws Exception {
		String locator = prop.getProperty(ElementNameInProp);
		System.out.println(locator);
		
		String locatorType = locator.split(":")[0];
		String locatorValue1 = locator.split(":")[1];
		String locatorValue = new String(locatorValue1.getBytes("ISO8859-1"), "UTF-8");
	
		if (locatorType.toLowerCase().equals("id"))
			return By.id(locatorValue);
		else if (locatorType.toLowerCase().equals("name"))
			return By.name(locatorValue);
		else if (locatorType.toLowerCase().equals("tag"))
			return By.tagName(locatorValue);
		else if (locatorType.toLowerCase().equals("class"))
			return By.className(locatorValue);
		else if (locatorType.toLowerCase().equals("css"))
			return By.cssSelector(locatorValue);
		else if (locatorType.toLowerCase().equals("link"))
			return By.linkText(locatorValue);
		else if (locatorType.toLowerCase().equals("xpath"))
			return By.xpath(locatorValue);
		else
			throw new Exception("元素找不到" + locatorType);
	}


}

ReadProperties.java
package com.edu.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.testng.annotations.Test;

public class ReadProperties {

	public static final String filePath="conf/conf.properties";
	

	public static String getPropertyValue(String key) throws IOException {
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream(filePath);
		prop.load(fis);
		fis.close();
		return prop.getProperty(key);
		
	}
}

appModules包主要用于实现复用的业务逻辑封装方法

Login_Action.java
package com.edu.appModules;

import org.openqa.selenium.WebDriver;

import com.edu.pageObjects.AddMessagePage;
import com.edu.utils.ReadProperties;
//test  www.baidu-test.com/login.html
//beta	www.baidu-beta.com/login.html
//live  www.baidu.com/login.html
public class AddMessage_Action {
	
	public static void addMessage(WebDriver wd,String message) throws Exception {
		
		String base_url=ReadProperties.getPropertyValue("baseUrl");
		AddMessagePage ap = new AddMessagePage(wd);
		wd.get(base_url+"/index.php/Detail/index/id/39");
		ap.getTxtArea().sendKeys(message);
		ap.getSubmit().click();
		Thread.sleep(3000);
		
	}

}

AddMessage_Action.java
package com.edu.appModules;

import org.openqa.selenium.WebDriver;

import com.edu.pageObjects.AddMessagePage;
import com.edu.utils.ReadProperties;
//test  www.baidu-test.com/login.html
//beta	www.baidu-beta.com/login.html
//live  www.baidu.com/login.html
public class AddMessage_Action {
	
	public static void addMessage(WebDriver wd,String message) throws Exception {
		
		String base_url=ReadProperties.getPropertyValue("baseUrl");
		AddMessagePage ap = new AddMessagePage(wd);
		wd.get(base_url+"/index.php/Detail/index/id/39");
		ap.getTxtArea().sendKeys(message);
		ap.getSubmit().click();
		Thread.sleep(3000);
		
	}

}

pageObjects包:用于实现被测试的页面对象

LoginPage.java
package com.edu.pageObjects;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.edu.utils.ObjectMap;

public class LoginPage {
	public WebElement element;
	public WebDriver driver;
	ObjectMap objMap = new ObjectMap("ObjectMap/login.properties");
	
	public LoginPage(WebDriver wd) {
		this.driver = wd;
	}
	
	public WebElement getLink() throws Exception {
		this.element =driver.findElement(objMap.getlocator("login.link"));
		return element;
	}
	public WebElement getUsername() throws Exception {
		this.element =driver.findElement(objMap.getlocator("login.name"));
		return element;
	}
	public WebElement getPassword() throws Exception {
		this.element =driver.findElement(objMap.getlocator("login.password"));
		return element;
	}
	
	public WebElement getSubmitBtn() throws Exception {
		this.element =driver.findElement(objMap.getlocator("login.submit"));
		return element;
	}

}

AddMessagePage.java
package com.edu.pageObjects;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.edu.utils.ObjectMap;

public class AddMessagePage {
	public WebElement element;
	public WebDriver driver;
	ObjectMap objMap = new ObjectMap("ObjectMap/addmessage.properties");
	
	public AddMessagePage(WebDriver wd) {
		this.driver = wd;
	}

	public WebElement getTxtArea() throws Exception {
		this.element =driver.findElement(objMap.getlocator("addmessage.textarea"));
		return element;
	}
	
	public WebElement getSubmit() throws Exception {
		this.element =driver.findElement(objMap.getlocator("addmessage.submit"));
		return element;
	}
}

testCases 包 :具体的测试方法

LoginTest.java
package com.edu.testCases;

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

import com.edu.appModules.Login_Action;
import com.edu.core.BaseTest;
import com.edu.dataprovider.NsDataProvider;
import com.edu.utils.Log;

public class LoginTest extends BaseTest{
	
	@Test(dataProvider="txt",dataProviderClass=NsDataProvider.class)
	public void loginSuccess(String u_name,String password)  {
		
		try {
			Login_Action.login(driver,u_name,password);
			Log.info("success");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.error("fail");
		}
		Assert.assertTrue(ifContains("�˳�"));
	}
	
	@Test
	public void loginFail() throws Exception {
		Login_Action.login(driver,"qingdao01","qing1111");
		Assert.assertTrue(ifContains("�û����������"));
	}
}

AddMessageTest.java
package com.edu.testCases;

import org.testng.annotations.Test;

import com.edu.appModules.AddMessage_Action;
import com.edu.appModules.Login_Action;
import com.edu.core.BaseTest;

public class AddMessageTest extends BaseTest{
	@Test
	public void addMessageSuccess() throws Exception {
		Login_Action.login(driver, "qingdao01", "123456");
		String message="增加成功";
		AddMessage_Action.addMessage(driver, message);
	}
	
	@Test
	public void addMessageFail() throws Exception {
		Login_Action.login(driver, "qingdao01", "123456");
		String message="";
		AddMessage_Action.addMessage(driver, message);
		
	}

}

dataprovider包:提供数据驱动的类,txt驱动,excel驱动,数据库的驱动

core:游览器启动、table元素读取

BaseTest.java
package com.edu.core;

import java.io.IOException;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeSuite;

import com.edu.utils.Log;
import com.edu.utils.ReadProperties;

public class BaseTest {

	public WebDriver driver = null;

	@BeforeClass
	public void startBrowser() throws InterruptedException, IOException {
		String firefox_driver = ReadProperties.getPropertyValue("gecko_driver");
		String firefox_path = ReadProperties.getPropertyValue("firefox_path");
		System.setProperty("webdriver.gecko.driver", firefox_driver);
		System.setProperty("webdriver.firefox.bin", firefox_path);
		driver = new FirefoxDriver();
		Log.info("打开浏览器");

		driver.get("http://localhost:8032/mymovie");
		Thread.sleep(3000);
	}

//	@AfterSuite
//	public void quitBrowser() {
//		this.driver.quit();
//	}

	public boolean ifContains(String content) {
		return driver.getPageSource().contains(content);
	}
}

Table.java
package com.edu.core;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

public class Table {
	WebElement table;
	public Table(WebElement table) {
		this.table=table;
	}
	
	public int getRowCount() {
		List<WebElement> rows = this.table.findElements(By.tagName("tr"));
		return  rows.size();
	}
	
	public int getCollCount() {
		List<WebElement> rows = this.table.findElements(By.tagName("tr"));
		return  rows.get(0).findElements(By.tagName("td")).size();
	}
	
	public WebElement getCell(int row,int col){
		List<WebElement> rows = this.table.findElements(By.tagName("tr"));
		WebElement currentRow=rows.get(row-1);
		List<WebElement> cols = currentRow.findElements(By.tagName("td"));
		WebElement currentCell=cols.get(col-1);
		return currentCell;
		
		
	}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/324994.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

js等于操作符和全等操作符(== 和 ===)的区别,在什么情况下使用

在JavaScript中&#xff0c;&#xff08;等于操作符&#xff09;和&#xff08;全等操作符&#xff09;都是用来比较两个值是否相等的工具&#xff0c;但它们有一些重要的区别。 会尝试进行类型转换&#xff0c;然后再比较。这意味着它可能会将不同类型的值转换为相同类型&…

Vue的使用

1、概述 https://cn.vuejs.org/ vscode Volar插件 2、创建项目 npm init vuelatest Project name: //只能小写cd projecName npm install / cnpm install nmp run dev目录结构&#xff1a;

Python3 索引下标及切片完全指南

介绍 Python 字符串数据类型是由一个或多个字符组成的序列&#xff0c;可以包含字母、数字、空格字符或符号。由于字符串是一个序列&#xff0c;我们可以通过索引和切片的方式访问它&#xff0c;就像访问其他基于序列的数据类型一样。 本教程将指导您通过索引访问字符串&…

Linux如何查看执行过命令的时间?

history调出历史命令&#xff0c;默认不带执行时的时间&#xff0c;下面进行配置&#xff0c;就可以实现了 小白教程&#xff0c;一看就会&#xff0c;一做就成。 1.在~/.bashrc文件中添加如下行 HISTTIMEFORMAT"%Y-%m-%d:%H-%M-%S:whoami:" export HISTTIMEFORMAT…

Centos 更换内核

文章目录 一、查看/更换系统内核1.1 查看当前运行环境的内核1.2 查看系统上所有可用内核1.3 切换内核方法一&#xff1a;通过启动菜单更换内核方法二&#xff1a;更换默认启动内核 二、安装内核2.1 使用ELRepo安装2.2 安装指定内核版本参考资料 一、查看/更换系统内核 1.1 查看…

new Handler(getMainLooper())与new Handler()的区别

Handler 在Android中是一种消息处理机制。 new Handler(); 创建handler对象&#xff0c;常用在已经初始化了 Looper 的线程中调用这个构造函数&#xff08;即非主线程&#xff09;&#xff0c;如果感觉不好理解&#xff0c;可以把Handler handler new Handler() 理解为常用在…

云计算概述(发展过程、定义、发展阶段、云计算榜单)(一)

云计算概述&#xff08;一&#xff09; &#xff08;发展过程、定义、发展阶段、云计算榜单&#xff09; 本文目录&#xff1a; 零、00时光宝盒 一、前言 二、云计算的发展过程 三、云计算的定义 四、云计算发展阶段 五、云计算公司榜单看云计算兴衰 六、参考资料 零、0…

【Docker】Docker基础教程

&#x1f996;我是Sam9029&#xff0c;一个前端 &#x1f431;‍&#x1f409;&#x1f431;‍&#x1f409;恭喜你&#xff0c;若此文你认为写的不错&#xff0c;不要吝啬你的赞扬&#xff0c;求收藏&#xff0c;求评论&#xff0c;求一个大大的赞&#xff01;&#x1f44d; 基…

php 的运算符

目录 1.算数运算符 2.自增自减 3.比较运算符 4.赋值运算 5.逻辑运算符 6.三元运算 1.算数运算符 运算符名称描述a b加和a - b减差a * b乘积a/b除a和b的商a % b模&#xff08;除法的余数&#xff09;a 除以 b的余数-a取负数a 的负数a.b并置连接两个字符串 <?php he…

读元宇宙改变一切笔记09_硬件与互操作性(下)

1. 移动互联网的继承者 1.1. 要想让元宇宙成为现实&#xff0c;需要开发新的标准&#xff0c;创建新的基础设施&#xff0c;可能还需要对长期存在的TCP/IP协议进行彻底改革 1.1.1. 采用新的设备和硬件&#xff0c;甚至可能打破技术巨头、独立开发者和终端用户之间的权利平衡 …

台式OLED透明屏的6大基本要素

台式 OLED 透明屏作为一种创新的显示技术&#xff0c;正逐渐走进人们的视野。本文将为您全面介绍台式 OLED 透明屏的各个方面&#xff0c;包括类别、尺寸、技术参数原理、应用、主要厂家&#xff08;尼伽&#xff09;以及价格因素。 一、类别台式 OLED 透明屏根据不同的需求和应…

微软Office 2021 批量许可版

软件介绍 微软办公软件套件Microsoft Office LTSC 2021 专业增强版2024年1月批量许可版更新推送&#xff01;Office2021正式版和Windows11系统同时于2021年10月份正式推出&#xff0c;Office LTSC 2021相比 Office2019正式版变化不太&#xff0c;最主要强化了LOGO设计趋势&…

《绝地求生》职业选手画面设置推荐 绝地求生画面怎么设置最好

《绝地求生》画面怎么设置最好是很多玩家心中的疑问&#xff0c;如果性能不是问题无疑高特效显示效果更好&#xff0c;但并不是所有画面参数都利于战斗&#xff0c;今天闲游盒带来分享的《绝地求生》职业选手画面设置推荐&#xff0c;赶紧来看看吧。 当前PUBG的图像设置的重要性…

深度学习中指定特定的GPU使用

目录 前言1. 问题所示2. 解决方法 前言 老生常谈&#xff0c;同样的问题&#xff0c;主要来源于&#xff1a;RuntimeError: CUDA error: out of memory 当使用完之后&#xff0c;想从其他方式调试&#xff0c;具体可看我这篇文章的&#xff1a;出现 CUDA out of memory 的解决…

【安全策略】前端 JS 安全对抗浏览器调试方法

一、概念解析 1.1 什么是接口加密 如今这个时代&#xff0c;数据已经变得越来越重要&#xff0c;网页和APP是主流的数据载体。而如果获取数据的接口没有设置任何的保护措施&#xff0c;那么数据的安全性将面临极大的威胁。不仅可能造成数据的轻易窃取和篡改&#xff0c;还可能…

AI教我学编程之C#类的基本概念(2)

前言 AI教我学编程之C#类的基本概念&#xff08;2&#xff09; 已经更新&#xff0c;欢迎道友们前往阅读&#xff0c;本节我们继续学习C#类的基本概念 目录 上节回顾 质疑 对话AI 特殊情况 发问 解释 数据/函数成员 类和程序–实现一个简单的程序 实现尝试 声明类 类的成员…

[笔记]深度学习入门 基于Python的理论与实现(一)

代码仓库 gitee 1. python 入门 1.5之前是python安装和基础语法, 我直接跳过了 1.5 Numpy 深度学习中经常出现数组和矩阵运算&#xff0c;Numpy 的数组类 numpy.array 提供了很多便捷的方法 1.5.1 导入 Numpy import numpy as np1.5.2 生成 Numpy 数组 np.array()&#xf…

C# wpf 实现任意控件(包括窗口)更多调整大小功能

WPF拖动改变大小系列 第一节 Grid内控件拖动调整大小 第二节 Canvas内控件拖动调整大小 第三节 窗口拖动调整大小 第四节 附加属性实现拖动调整大小 第五章 拓展更多调整大小功能&#xff08;本章&#xff09; 文章目录 WPF拖动改变大小系列前言一、添加的功能1、任意控件Drag…

Vant2组件的使用

组件地址&#xff1a;Vant 2 - Mobile UI Components built on VueMobile UI Components built on Vuehttps://vant-contrib.gitee.io/vant/v2/#/zh-CN/ 通过 npm 安装 # Vue 3 项目&#xff0c;安装最新版 Vant&#xff1a; npm i vant -S # Vue 2 项目&#xff0c;安装 Va…