UI自动化测试框架

news2025/1/10 12:07:36

文章目录

    • 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;
		
		
	}

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

屏幕录制软件有哪些?强烈推荐5款免费好用录屏软件

录制全屏视频是制作视频教程、评论、游戏等内容的绝佳方式。它可以包括您计算机屏幕上的任何活动以及您的音频和网络摄像头。特别是&#xff0c;屏幕录像机对喜欢创建软件评论的视频博主很有帮助。如果您是其中之一&#xff0c;那么好消息是您可以在网络上找到很多屏幕录制应用…

纯c++简易的迷宫小游戏

一个用c写的黑框框迷宫 适合新手入门学习 也适合大学生小作业 下面附上代码 总体思路 初始化游戏界面&#xff1a;设置迷宫的大小&#xff08;WIDTH和HEIGH&#xff09;&#xff0c;生成迷宫地图&#xff08;map&#xff09;&#xff0c;包括墙壁、空地、起点和终点。显示…

怿星科技测试实验室获CNAS实验室认可,汽车以太网检测能力达国际标准

2023年12月27日&#xff0c;上海怿星电子科技有限公司测试实验室&#xff08;下称&#xff1a;EPT LABS&#xff09;通过CNAS实验室认可批准&#xff0c;并于2024年1月5日正式取得CNAS实验室认可证书&#xff08;注册号CNAS L19826&#xff09;&#xff0c;标志着怿星科技的实验…

SpringBoot3自动配置原理

​​​​​​自动配置 遵循约定大约配置的原则&#xff0c;在boot程序启动后&#xff0c;起步依赖中的一些bean对象会自动注入到ioc容器 看一下我们前面写的代码有没有达到自动配置的效果呢&#xff1f; 没有自动&#xff0c;我们写了配置类&#xff0c;写了Import注解&#…

一台电脑如何通过另一台联网电脑访问网络

电脑A没有连接网络&#xff0c;电脑B已经连接wifi。 电脑A如何通过访问电脑B从而连接网络&#xff1f; 1. 将这2台电脑用网线直连 2. 电脑B打开【网络和Internet设置】 3. 右键点击WLAN&#xff0c;选择属性&#xff0c;进入共享tab页面&#xff0c;勾选【允许其他网络用户通过…

超融合之道:亚信安慧AntDB 8.0版本引领数据库创新

在当今多变的数据应用场景中&#xff0c;AntDB作为行业领先的超融合流式实时数仓&#xff0c;秉承着“融合实时”的研发理念&#xff0c;全面应对企业日益复杂的数据处理需求。通过SQL接口访问多种执行引擎&#xff0c;AntDB在实现交易、分析等多重能力的“超融合”方面取得了显…

nacos配置yml空格报错提示

错误格式 正确格式 spring:redis: # redis配置host: 192.168.30.113 # IPport: 6379 # 端口password: # 密码connect-timeout: 10s # 连接超时时间lettuce: # lettuce redis客户端配置pool: # 连接池配置max-active: 8 # 连接池最大连接数&#xff08;使用负值表示没有限…

android studio设置gradle和gradle JDK版本

文章目录 1.gradle JDK版本2.gradle版本 1.gradle JDK版本 file -> project structure -> SDK Location -> Gradle Settings -> Gradle JDK -> Download JDK 2.gradle版本 file -> project structure -> Project

打造创新的金融数据平台,加速数字化和智能化转型丨PingCAP 官网金融行业专区上线

自诞生以来&#xff0c;TiDB 的原生分布式架构在强一致性、高可用性和可扩展性等方面与金融级业务需求高度契合&#xff0c;早期版本即为包括北京银行在内的金融用户提供服务。 TiDB 的核心能力始终源自与中国金融用户的共同创造。作为金融级分布式数据库&#xff0c;TiDB 在国…

东南亚潜力巨大,下一个变现增长点!Flat Ads助力休闲游戏出海

近年来,得益于庞大的消费市场和人口红利,东南亚经济飞速发展,尤其在移动互联网和数字经济领域表现亮眼。巨大的发展空间吸引了众多出海者布局,而东南亚有利的人口结构、不断增长的财富以及日益城市化的人口为数字经济的未来增长奠定了基础。那么,2024年游戏出海东南亚,是否仍有…

Zabbix补充扩展

目录 1.自定义监控内容 客户端配置 2.zabbix自动发现与自动注册 自动发现 在服务端和客户端上配置 hosts 解析 在Web页面配置自动发现 自动注册 3.部署zabbix代理服务器 下载zabbix-proxy以及数据库 启动zabbix-proxy及添加hosts解析 在Web页面配置agent代理 配置a…

S1D13L02 VGA简单的液晶控制器

S1D13L02是一款简单、低成本、低功耗、多用途的液晶控制器&#xff0c;具有一个1024 KB的嵌入式SRAM显示缓冲区。 S1D13L02提供了一个灵活的&#xff0c;但易于开发的显示系统&#xff0c;适合于满足嵌入式市场的需求&#xff0c;如工厂自动化、医疗设备和 办公自动化应用。 S1…

过滤器、拦截器、AOP、ControllerAdvcie执行顺序对比

过滤器Filter 简介 来自J2EE中的Servlet技术实现原理&#xff1a;基于servlet的函数回调实现只可以获取到请求中的request和response&#xff0c;无法获取到响应方法的信息可以拦截所有请求支持使用xml配置和注解配置应用场景&#xff1a;权限认证、敏感词检测、访问日志记录…

JVM对象创建与内存分配机制剖析

欢迎大家关注我的微信公众号&#xff1a; 传送门&#xff1a;JVM内存模型深度剖析与优化 目录 对象的创建 对象大小与指针压缩 对象内存分配 对象内存回收 对象的创建 对象创建的主要流程: 1.类加载检查 虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的…

GC6106 双通道5V低电压步进电机驱动芯片——低噪声、低振动

GC6106是双通道5V低电压步进电机驱动器&#xff0c;具有低噪声、低振动的特点&#xff0c;特别适用于相机的变焦和对焦系统&#xff0c;万向节和其他精密&#xff0c;低噪声STM控制系统。该芯片为每个通道集成了256微步驱动器。我SPl接口&#xff0c;用户可以方便地调整驱动器的…

设计模式入门

0. 类图 1. 设计原则 1.单一职责原则&#xff1a;每个类只有一个功能 2.开放封闭原则&#xff1a;模块和函数应该对扩展开放(对提供方)&#xff0c;对修改关闭(对使用方) 3.里氏代换原则&#xff1a;子类拥有父类的所有方法和属性&#xff0c;从而可以减少创建类的工作量 4.依…

【MySQL高级】——性能分析

数据库调优中&#xff0c;目标是 响应时间更快&#xff0c;吞吐量更大&#xff0c;利用宏观的监控工具和微观的日志分析帮助我们快速找到调优的思路和方式。 1. 数据库服务器优化步骤 整个流程划分成了 观察&#xff08;Show status&#xff09; 和 行动&#xff08;Action&am…

业财融合:解密企业管理的黄金钥匙

本文提炼总结自专刊《上市公司如何打好合规与增长的双赢之战》。全书40页&#xff0c;出品方纷享销客市场部。如有需要&#xff0c;请阅读原版电子书&#xff1a;《上市公司如何打好合规与增长的双赢之战》 目 录 一、什么是业财融合&#xff1f; 二、财务部门面临的挑战…

超好用的写作软件,下面这5款AI写作你一定要知道

写作是一项需要耐心和技巧的工作&#xff0c;而在数字化时代&#xff0c;我们可以借助各种写作软件来提高效率和质量。在市场上有许多AI自动写作软件&#xff0c;它们能够帮助我们生成文章、提供创意和编辑建议。在本文中&#xff0c;我将向大家推荐五款功能强大且好用的写作软…

腾讯云把向量数据库“卷”到哪一步了?

“不是我不明白&#xff0c;这世界变化快”&#xff0c;崔健在20世纪写下的这句歌词&#xff0c;放在刚刚过去的2023年&#xff0c;也同样适用。技术风向的变化之快&#xff0c;让不少人感到惊讶&#xff0c;向量数据库这一年的潮起潮落&#xff0c;就是一个典型的例子。 2023年…