关于selenium的CI、框架……
这段时间除了项目测试外,主要在做web自动化的事情,大致总结一下吧,总体的设计模式pageobject+pagefactory+testng的数据驱动,项目用maven来构建,使用jenkins集成,用grid分布式部署,支持并发。下面分别来简单说下注意事项吧。
一、jenkins
代码放在git上,除了常规的设置git插件外,需要注意
1.触发构建
选择,Build periodically。0 * * * * 表示的就是每个小时的第 0 分钟执行一次构建。参数含义:
- 第一个参数代表的是分钟 minute,取值 0~59;
- 第二个参数代表的是小时 hour,取值 0~23;
- 第三个参数代表的是天 day,取值 1~31;
- 第四个参数代表的是月 month,取值 1~12;
- 最后一个参数代表的是星期 week,取值 0~7,0 和 7 都是表示星期天。
2.构建步骤
运行pom文件,命令是
clean install compile test-compile test
一定要把maven中的main和test一起编译。
3.测试报告
目前公司的Jenkins安装的插件是publish testng results,路径默认即可 。**/testng-results.xml,效果图如下:
4.发送邮件
邮件触发选择always,content我暂时设计了一个模板,以后再优化,效果如下
代码如下:
hi all,<br/><hr/> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>qiaoyeye</title> <style type="text/css"> <!-- .STYLE1 { font-size: 18px; font-weight: bold; color: #FF0000; } .STYLE2 { font-size: 14px; font-weight: bold; } .STYLE3 { color: #00FF00; font-weight: bold; font-size: 14px; } .STYLE4 { color: #FF0000; font-weight: bold; font-size: 14px; } .STYLE5 { color: #FFFF00; font-weight: bold; font-size: 14px; } .STYLE6 {font-size: 12px} --> </style> </head> <body> <span class="STYLE1">构建结果 - ${BUILD_STATUS}</span> <br /> <br /> <br /> <br /> <br /> <span class="STYLE2">构建信息</span> <hr /> <br /> <ul> <li>项目名称:${PROJECT_NAME}</li> <li>构建编号:${BUILD_NUMBER}</li> <li>构建时间:${BUILD_ID}</li> <li>触发原因:${CAUSE}</li> <li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li> <li>构建URL:<a href="${BUILD_URL}">${BUILD_URL}</a></li> <li>项目URL:<a href="${PROJECT_URL}">${PROJECT_URL}</li> <li>工作目录:<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li> </ul> <br /> <br /> <span class="STYLE2">测试概览</span> <hr /> <br /> <table width="700" height="64" border="1"> <tr> <td bgcolor="#CCCCCC"><div align="center" class="STYLE2">total</div></td> <td bgcolor="#CCCCCC"><div align="center" class="STYLE3">passed</div></td> <td bgcolor="#CCCCCC"><div align="center" class="STYLE4">failed</div></td> <td bgcolor="#CCCCCC"><div align="center" class="STYLE5">skipped</div></td> </tr> <tr> <td><div align="center"><span class="STYLE6"> ${TEST_COUNTS, var="total"}</span></div></td> <td><div align="center"><span class="STYLE6"> ${TEST_COUNTS, var="pass"}</span></div></td> <td><div align="center"><span class="STYLE6"> ${TEST_COUNTS, var="fail"}</span></div></td> <td><div align="center"><span class="STYLE6"> ${TEST_COUNTS, var="skip"}</span></div></td> </tr> </table> <br /> <br /> <span class="STYLE2">failure log:</span> <hr /> $FAILED_TESTS <br /> $PASSED_TESTS <br /> $SKIPPED_TESTS <br /> </body> </html> <br/><hr/> (本邮件是程序自动下发的,请勿回复!)<br/><hr/>
5.可以把失败的截图作为附件添加
projectjobname/imgfilename/*.png
**/ExceptionScreenshotImg/**/*.png
二、maven
主要是pom文件,需要在pom中添加对testng的支持
<build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> <configuration> <suiteXmlFiles> <!-- <suiteXmlFile> --> <file>src/test/java/OmsWebAuto.xml</file> <!-- </suiteXmlFile> --> </suiteXmlFiles> </configuration> </plugin>
pom对reportNG的支持
<!-- reportng --> <dependency> <groupId>org.uncommons</groupId> <artifactId>reportng</artifactId> <version>1.1.2</version> <scope>test</scope> <exclusions> <exclusion> <groupId>org.testng</groupId> <artifactId>testng</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>velocity</groupId> <artifactId>velocity</artifactId> <version>1.4</version> <scope>test</scope> </dependency> <!-- 加入reportNG和testng的插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> <properties> <property> <name>usedefaultlisteners</name> <value>false</value> </property> <property> <name>listener</name> <value>org.uncommons.reportng.HTMLReporter, org.uncommons.reportng.JUnitXMLReporter</value> </property> </properties> <suiteXmlFiles> <!-- <suiteXmlFile> --> <file>src/test/java/International.xml</file> <!-- </suiteXmlFile> --> </suiteXmlFiles> </configuration> </plugin>
三、框架
1.合理利用selenium的监听事件
可以把一些log或者经常调用的方法等放在监听事件类里,只需要自己新建一个类实现WebDriverEventListener即可,好处是在后面的代码中不需要在写一堆方法或频繁调用了,效果真的不错。注册监听的方法:
private static EventFiringWebDriver registerEvent(WebDriver driver) { EventFiringWebDriver event = new EventFiringWebDriver(driver); BaseEventListener eventlis = new BaseEventListener(); event.register(eventlis); return event; }
2. 利用testng的监听事件
如失败自动截图,参考我的文章:
selenium遇到异常自动截图
失败自动重跑,抽时间再整理成文章:
等……
3.所有用例只启动浏览器、登录、关闭浏览器一次
要想做到这点,首先要明白testng的生命周期,可以参考我的这边文章http://www.cnblogs.com/qiaoyeye/p/5317566.html
然后核心思想是保证所有的测试类在整个生命周期内用的是同一个webdriver对象,一定要理解,要想做到这一点,就必须单独建立一个类,包含初始化webdriver的方法和webdriver的全局变量,放在合适的testng注解内,其他所有的测试类,都调用该类的webdriver。举例如下:
- webdriver初始化类:
/** * 在整个测试中,只启动浏览器、登录至主页、关闭浏览器一次。所有测试类的driver=TestSuite.driver,以保证共用的是一个driver。 * @author QiaoJiafei * @version 创建时间:2016年5月13日 下午6:48:41 * 类说明 */ public class TestSuite{ public static WebDriver driver; @BeforeSuite public void befSuite() { driver = DriverFactory.setUpDriver(); visitorURL(); Login.login(driver); //直接进入订单系统页面 HomePage homepage = new HomePage(driver); homepage.jumpProduct(); } private void visitorURL() { String url = OptionFile.readProperties("./src/test/resources/logininfo.properties", "URL"); driver.get(url); } @AfterSuite public void aftSuite() { DriverFactory.tearDownDriver(driver); } }
- 测试类,注意这里把testsuite的driver赋值给了driver,保证了整个生命周期用的都是同一个driver
public class TestOrderSearch extends BaseTestClass{ @Test public void testOrderSerach() { driver = TestSuite.driver; OrderHomePage odp = new OrderHomePage(driver); OrderSearchPage osp = odp.jumpOrderSearch(); osp.searchOrder(); osp.clickOrderDetail(); } }
- Driverfactory就是一个初始化和销毁driver的工厂类。
4.pafactory遇到iframe怎么办
我的解决办法是三种,在同一个类内解决,不同类解决,内部类解决。
- 同一个类
在同一个类中的话,在使用iframe中的元素时一定要先切换ifame,使用完元素后,要记得切回主体。这种办法适合iframe中要使用的元素比较少时使用。
- 内部类
在内部类的话,等于把处理iframe的元素抽象到了一个类中,切换iframe和切回主体都在内部类中,这样其他类只需要调用内部类即可,不需要在关心iframe的处理,适合iframe中有适量的元素处理
public class Inner extends BasePage{ public Inner(WebDriver driver) { super(driver); this.toFrame("ueditor_0"); } // @FindBy(xpath="/html/body") WebElement rich_body; public void setContent() { this.setRichTextBox(rich_body, "web ui auto test"); this.toDefaultContent(); } }
- 不同的类
和内部类类似,使用要在iframe处理的元素比较多,就可以单独拉出啦作为一个类处理。
5.活用反射
java的反射真的太好了,目前主要用在:
- 在数据驱动动态获取必要参数,因为testng的数据驱动不支持主动调用传参的。
- 自动截图中,自动以运行的类名来命名文件夹,然后以方法名+时间戳来命名图片。
- pagefactory初始化之前,从property文件中获取当前正在运行的类的标题,key是类名,value是标题,这样只需要配置好property文件就行,省了不少麻烦。
四、grid
这个没什么好说的,一台电脑启动hub,然后在不同的机器上启动node,注册到该hub上,grid会根据框架对浏览器的配置来分配相应的node启动浏览器测试,selenium官网上有很多这方面的介绍,这里只介绍下我常用的命令
- hub:
java -jar selenium-server-standalone-2.53.0.jar -role hub
- node1:
java -Dwebdriver.chrome.driver=C:\selenium\node_chrome32_windows\driver\chromedriver.exe -jar selenium-server-standalone-2.53.0.jar -role node -hub http://192.168.15.54:4444/grid/register -maxSession 20 -browser "browserName=chrome,platform=WINDOWS,maxInstances=20" -port 5556
- node2
- …………
上面的命令更换浏览器名称、端口、路径即可
目前只是初步成型,后面还有很多工作要做。
作者:乔叶叶
博客地址:http://www.cnblogs.com/qiaoyeye/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
******************************************************************************************************************************************
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?