基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一个WebUI自动化框架
2021/12/23 9:09:00
本文主要是介绍基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一个WebUI自动化框架,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
本次框架使用Maven作为代码构建管理,引用了PO模式,将整体的代码分成了页面层、用例层、业务逻辑层。
框架搭建流程:
1、在pom.xml中引入依赖:
<!-- https://mvnrepository.com/artifact/io.appium/java-client --> <dependency> <groupId>io.appium</groupId> <artifactId>java-client</artifactId> <version>7.0.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.testng/testng --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.0.0</version> <scope>test</scope> </dependency> <!--日志组件依赖--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
2、在resources目录下添加好自己浏览器对应版本的chromedriver.exe,geckodriver.exe,IEDriverServer.exe;再添加一个log4j.properties文件,用于配置日志的打印格式信息,添加如下信息:
#根logger主要定义log4j支持的日志级别及输出目的地 log4j.rootLogger = DEBUG,console,file ###输出信息到控制台配置### #表示输出到控制台 log4j.appender.console = org.apache.log4j.ConsoleAppender #将System.out作为输出 log4j.appender.console.Target = System.out #使用灵活的布局展示日志信息 log4j.appender.console.layout = org.apache.log4j.PatternLayout #日志详细输出信息样式 log4j.appender.console.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n ###输出信息到文件中配置### #每天产生一个日志文件 log4j.appender.file = org.apache.log4j.DailyRollingFileAppender #输出文件目的地 log4j.appender.file.File = log/web_auto.log #新的日志信息是否追加到旧的日志文件末尾 log4j.appender.file.Append = true #使用灵活的布局展示日志信息 log4j.appender.file.layout = org.apache.log4j.PatternLayout #日志详细输出信息样式 log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
3、将页面层的共性操作提取到common包下的BasePage类,将用例层的共性操作提取到common包下的BaseTest类。
package com.lrc.common; import org.apache.log4j.Logger; import org.openqa.selenium.Alert; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; /** * @param * @author lrc * @create 2021/12/13 * @return * @description 封装页面层的公用方法 **/ public class BasePage { private static Logger logger = Logger.getLogger(BasePage.class); /** * 显式等待元素可见二次封装 * @param driver 驱动对象 * @param by 元素定位信息 */ public WebElement waitElementVisible(RemoteWebDriver driver, By by ){ WebElement webElement = null; try { //1、实例化WebDriverWait 超时时间10s WebDriverWait webDriverWait = new WebDriverWait(driver,10); //2、通过until方法等到某个条件满足时为止 webElement = webDriverWait.until(ExpectedConditions.visibilityOfElementLocated(by)); }catch (Exception e){ logger.error("定位元素【"+by+"】异常"); } return webElement; } /** * 显式等待元素可被点击二次封装 * @param driver 驱动对象 * @param by 元素定位信息 */ public WebElement waitElementClickable(RemoteWebDriver driver, By by ){ WebElement webElement =null; try { //1、实例化WebDriverWait 超时时间10s WebDriverWait webDriverWait = new WebDriverWait(driver, 10); //2、通过until方法等到某个条件满足时为止 webElement = webDriverWait.until(ExpectedConditions.elementToBeClickable(by)); }catch (Exception e){ logger.error("定位元素【"+by+"】异常"); } return webElement; } /** * 输入框输入数据通用方法 * @param driver 驱动对象 * @param by 元素定位信息 * @param data 输入的数据 */ public void sendKey(RemoteWebDriver driver, By by,String data,String elementName){ logger.info("往元素【"+elementName+"】输入数据【"+data+"】"); waitElementVisible(driver,by).sendKeys(data); } /** * 点击操作的通用方法 * @param driver 驱动对象 * @param by 元素定位信息 */ public void click(RemoteWebDriver driver, By by,String elementName){ logger.info("对元素【"+elementName+"】进行点击"); waitElementClickable(driver,by).click(); } /** * 获取元素文本方法封装 * @param driver 驱动对象 * @param by 元素定位信息 * @param elementName 元素名称 * @return */ public String getText(RemoteWebDriver driver,By by,String elementName){ String text=waitElementVisible(driver,by).getText(); logger.info("获取元素【"+elementName+"】文本【"+text+"】"); return text; } /** * 切换到指定IFrame封装 * @param driver 驱动对象 * @param by 元素定位信息 * @param frameInfo 自定义frame信息 */ public void switchFrame(RemoteWebDriver driver,By by,String frameInfo){ WebElement element = waitElementVisible(driver, by); logger.info("切换IFrame:"+frameInfo); driver.switchTo().frame(element); } /** * 从IFrame中切换到默认页面封装 * @param driver 驱动对象 */ public void switchDefaultFrame(RemoteWebDriver driver){ logger.info("切换回默认的页面"); driver.switchTo().defaultContent(); } /** * Alert弹窗切换 * @param driver 驱动对象 */ public void switchAlert(RemoteWebDriver driver){ logger.info("切换到alert窗口"); Alert alert = driver.switchTo().alert(); // alert.accept(); //点击确定 //alert.dismiss(); //点击取消 alert.getText(); //获取弹窗文本 } }
package com.lrc.common; import org.apache.log4j.Logger; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.Assert; import java.util.Set; /** * @param * @author lrc * @create 2021/12/13 * @return * @description 封装用例层的公用方法 **/ public class BaseTest { private static Logger logger = Logger.getLogger(BaseTest.class); public RemoteWebDriver driver; /** * 打开所有浏览器通用方法封装 * * @param browserName 浏览器名 */ public void openBrowser(String browserName) { RemoteWebDriver webDriver = null; if ("chrome".equalsIgnoreCase(browserName)) { System.setProperty("webdriver.chrome.driver", "src\\test\\resources\\chromedriver.exe"); webDriver = new ChromeDriver(); logger.info("====================打开了chrome浏览器====================="); } else if ("firefox".equalsIgnoreCase(browserName)) { System.setProperty("webdriver.gecko.driver", "src\\test\\resources\\geckodriver.exe"); webDriver = new FirefoxDriver(); logger.info("====================打开了Firefox浏览器====================="); } else if ("ie".equalsIgnoreCase(browserName)) { DesiredCapabilities capabilities = new DesiredCapabilities(); //取消IE安全设置(忽略IE的Protected Mode的设置) capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); //忽略浏览器缩放设置 capabilities.setCapability(InternetExplorerDriver.IGNORE_ZOOM_SETTING, true); System.setProperty("webdriver.ie.driver", "src\\test\\resources\\IEDriverServer.exe"); webDriver = new InternetExplorerDriver(capabilities); logger.info("====================打开了IE浏览器====================="); } driver= webDriver; } /** * 关闭浏览器通用方法 */ public void closeBrowser(){ logger.info("====================关闭浏览器====================="); driver.close(); } /** * 退出浏览器通用方法 */ public void quitBrowser(){ logger.info("====================退出浏览器====================="); driver.quit(); } /** * 最大化浏览器 */ public void maxBrowser(){ logger.info("================最大化浏览器==================="); driver.manage().window().maximize(); } /** * 访问指定网址 * @param url 访问地址 */ public void toURL(String url){ logger.info("================访问网址:==================="+url); driver.get(url); } /** * 封装的通用切换窗口的方法-根据对应窗口的标题来切换 * @param title 窗口标题 */ public void switchWindowWithTitle(String title){ Set<String> allWindowHandles = driver.getWindowHandles(); for (String windowHandle: allWindowHandles){ //根据窗口的标题来进行判断 if(title.equals(driver.getTitle())){ break; }else { logger.info("切换到标题为:【"+title+"】的窗口"); driver.switchTo().window(windowHandle); } } } /** * 封装的通用切换窗口的方法-根据对应窗口的url来切换 * @param url 窗口url */ public void switchWindowWithURL(String url){ Set<String> allWindowHandles = driver.getWindowHandles(); for (String windowHandle: allWindowHandles){ //根据窗口的URL来进行判断 if (url.equals(driver.getCurrentUrl())){ break; }else { logger.info("切换到url为:【"+url+"】的窗口"); driver.switchTo().window(windowHandle); } } } public void myAssertTrue(boolean condition,String assertDescription){ logger.info("断言:【"+assertDescription+"】条件表达式【"+condition+"】"); Assert.assertTrue(condition); } public void myAssertEquals(String actual,String expected,String assertDescription){ logger.info("断言:【"+assertDescription+"】实际值【"+actual+"】期望值【"+expected+"】"); Assert.assertEquals(actual,expected); } public void myAssertEquals(int actual,int expected,String assertDescription){ logger.info("断言:【"+assertDescription+"】实际值【"+actual+"】期望值【"+expected+"】"); Assert.assertEquals(actual,expected); } public void myAssertEquals(double actual,double expected,String assertDescription){ logger.info("断言:【"+assertDescription+"】实际值【"+actual+"】期望值【"+expected+"】"); Assert.assertEquals(actual,expected); } public void myAssertEquals(float actual,float expected,String assertDescription){ logger.info("断言:【"+assertDescription+"】实际值【"+actual+"】期望值【"+expected+"】"); Assert.assertEquals(actual,expected); } public void myAssertEquals(Object actual,Object expected,String assertDescription){ logger.info("断言:【"+assertDescription+"】实际值【"+actual+"】期望值【"+expected+"】"); Assert.assertEquals(actual,expected); } }
4、新建一个config包,新建一个全局配置数据类GlobalDatas,用于统筹管理项目的基础信息。
package com.lrc.config; /** * @param * @author lrc * @create 2021/12/13 * @return * @description **/ public class GlobalDatas { //配置的浏览器 public static final String BROWSER_NAME="chrome"; //测试系统的登录账号 public static final String USER_NAME="筱筱创"; //测试系统的登录密码 public static final String USER_PASSWORD="123456"; //项目的URL地址 public static final String INDEX_URL="https://www.baidu.com"; //万能验证码 public static final String OMNIPOTENT_CODE="XXXX"; }
5、在page包下写一个百度页面的元素定位信息与操作方法:
package com.lrc.page; import com.lrc.common.BasePage; import org.openqa.selenium.By; import org.openqa.selenium.remote.RemoteWebDriver; /** * @param * @author lrc * @create 2021/12/22 * @return * @description **/ public class BaiduPage extends BasePage { private RemoteWebDriver driver; //搜索输入框 private By searchInputBy=By.id("kw"); //百度一下按钮 private By searchSubmitBy=By.id("su"); //新闻链接 private By newsLinkBy=By.xpath("//a[text()='新闻']"); //hao123链接 private By hao123LinkBy=By.xpath("//a[text()='hao123']"); //地图链接 private By mapLinkBy=By.xpath("//a[text()='地图']"); //贴吧链接 private By tieBaLinkBy=By.xpath("//a[text()='贴吧']"); //视频链接 private By videoLinkBy=By.xpath("//div[@id='s-top-left']/a[text()='视频']"); //图片链接 private By pictureLinkBy=By.xpath("//div[@id='s-top-left']/a[text()=' 图片']"); //网盘链接 private By panLinkBy=By.xpath("//div[@id='s-top-left']/a[text()='网盘']"); //更多链接 private By moreLinkBy=By.xpath("//div[@class='mnav s-top-more-btn']/a[text()='更多']"); //生成百度页面的构造方法 public BaiduPage(RemoteWebDriver driver) { this.driver = driver; } //在页面层封装向百度搜索框输入数据的方法 public void inputData(String data){ sendKey(driver,searchInputBy, data,"百度搜索框"); } //在页面层封装点击【百度一下】的方法 public void clickBaidu(){ click(driver,searchSubmitBy,"百度一下按钮"); } //在页面层封装点击"新闻"的方法 public void clickNews(){ click(driver,newsLinkBy,"新闻链接"); } //在页面层封装点击"hao123"的方法 public void clickHao123(){ click(driver,hao123LinkBy,"hao123链接"); } //在页面层封装点击"地图"的方法 public void clickMap(){ click(driver,mapLinkBy,"地图链接"); } //在页面层封装点击"贴吧"的方法 public void clickTieBa(){ click(driver,tieBaLinkBy,"贴吧链接"); } //在页面层封装点击"视频"的方法 public void clickVideo(){ click(driver,videoLinkBy,"视频链接"); } //在页面层封装点击"图片"的方法 public void clickPicture(){ click(driver,pictureLinkBy,"图片链接"); } //在页面层封装点击"网盘"的方法 public void clickPan(){ click(driver,panLinkBy,"网盘链接"); } }
6、在testcases用例层中编写百度页面的测试用例
package com.lrc.testcases; import com.lrc.common.BaseTest; import com.lrc.config.GlobalDatas; import com.lrc.page.BaiduPage; import org.testng.annotations.*; /** * @param * @author lrc * @create 2021/12/22 * @return * @description **/ public class TestBaidu extends BaseTest { @BeforeMethod public void setup(){ //用例前置 //1、打开浏览器 openBrowser(GlobalDatas.BROWSER_NAME); maxBrowser(); //2、进入登录页面 toURL(GlobalDatas.INDEX_URL); } //测试百度搜索功能 @Test public void test_baidu_success(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.inputData(GlobalDatas.USER_NAME); baiduPage.clickBaidu(); } //测试点击【新闻链接】 @Test public void test_click_new(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.clickNews(); } //测试点击【hao123】 @Test public void test_click_hao123(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.clickHao123(); } //测试点击【地图】 @Test public void test_click_map(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.clickMap(); } //测试点击【贴吧】 @Test public void test_click_tieBa(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.clickTieBa(); } //测试点击【视频】 @Test public void test_click_video(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.clickVideo(); } //测试点击【图片】 @Test public void test_click_picture(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.clickPicture(); } //测试点击【网盘】 @Test public void test_click_pan(){ BaiduPage baiduPage=new BaiduPage(driver); baiduPage.clickPan(); } @AfterMethod public void teardown(){ //用例后置 //退出浏览器 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } quitBrowser(); } }
至此,测试框架的基本雏形已经搭建好了,在TestBaidu测试类右击执行即可运行测试用例了。
后续工作:
(1)实际复杂业务可能会涉及到很多个页面,比如:商城下单业务,每个用例执行的时候都需要先进行登录,选择商品等操作,此处只是设计了页面层、用例层,维护起来就显得很乏力,因为这里每个用例都需要执行登录,选择商品等操作,非常繁琐,为了解决这个问题,就需要添加个业务逻辑层,将很多用例都必须要执行到的共性操作封装到这个层,在用例层只需要调用业务逻辑层的方法即可完成复杂业务,使得维护起来方便许多
(2)使用Testng提供的DataProvider实现数据驱动,使得测试数据与用例能够解耦
(3)引入Allure报表,统计用例执行情况
(4)引入失败用例截图与重试机制,提高代码稳定性
(5)引入并行测试机制,提高代码执行效率
(6)配置GitLab/Github/SVN代码仓库,配置Jenkins拉取仓库代码,配置Jenkins自动化构建执行,输出Allure报告,发送邮件/钉钉等
这篇关于基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一个WebUI自动化框架的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南