一个简单的Web UI自动化测试框架Java实现

news2024/11/20 6:12:44

 🔥 交流讨论:欢迎加入我们一起学习!

🔥 资源分享耗时200+小时精选的「软件测试」资料包

🔥 教程推荐:火遍全网的《软件测试》教程  

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

简介

这个框架的名字叫OAT,全称Object-Oriented  Automation Test.这个框架的思想借助于Tellurium框架.他的主要功能是将页面信息及行为存储在Java 对象中,然后在脚本中引用页面的行为.自动化程序最终由许多的页面行为组成.这个框架默认使用Selenium1驱动,并且可以通过编程使用其他驱动,因 为OAT是面向接口的.

以下以google home page的demo为例,介绍这个基于Annoation和反射的框架基本运行原理.

page对象

  1. //存储页面URL  
  2. @OatPage("webhp")   
  3. public class GooglePage extends Page{  
  4.     @Element("q") // 搜索输入框的定位符  
  5.     private TextField textField;  
  6.     @Element("btnG") // 搜索按钮的定位符  
  7.     private Button searchButton;  
  8.       
  9.     // TextField和Button有共同的祖先类Element  
  10.     public TextField getTextField() {  
  11.         return textField;  
  12.     }  
  13.     public Button getSearchButton() {  
  14.         return searchButton;  
  15.     }  
  16.     //进行一次搜索  
  17.     public void doSearch(String q){  
  18.         this.textField.type(q);  
  19.         this.searchButton.click();  
  20.     }     
  21.   
  22. }  

 TextField和button类

  1. // Element子类,有自己独特的行为  
  2. public class TextField extends Element {  
  3.       
  4.     public void type(String value) {  
  5.         vendor.type(locator, value);  
  6.     }  
  7.       
  8.     public boolean idEditable(){  
  9.         return vendor.isEditable(locator);        
  10.     }  
  11.       
  12.     public String getValue() {  
  13.         return vendor.getAttribute(locator);  
  14.     }  
  15.   
  16. }  
  17. // 同样是Element的子类,有自己行为  
  18. public class Button extends Element {  
  19.       
  20.       
  21.     public void click() {  
  22.         vendor.click(locator);  
  23.     }  
  24.       
  25.     public void clickAndWaitToLoad(Page page){  
  26.         click();  
  27.         page.waitToLoad();  
  28.     }  
  29.       
  30.     public void clickAndWaitToLoad(Page page, long timeout) {  
  31.         click();  
  32.         page.waitToLoad(timeout);  
  33.     }  
  34.       
  35.     public void clickAndWaitToLoad(Element element, long timeout) {  
  36.         click();  
  37.         element.waitToLoad(timeout);  
  38.     }  
  39.       
  40.     public void clickAndWaitToLoad(Element element) {  
  41.         clickAndWaitToLoad(element, ELEMENT_DEFAULT_TIMEOUT);  
  42.     }  
  43.       
  44. }  

自动化测试脚本代码

  1. import junit.framework.Assert;  
  2.   
  3. import org.junit.After;  
  4. import org.junit.Before;  
  5. import org.junit.Test;  
  6.   
  7. import com.thoughtworks.selenium.DefaultSelenium;  
  8. import com.thoughtworks.selenium.Selenium;  
  9.   
  10. public class GoogleSearchTestExample1 {  
  11.       
  12.     private String serverUrl = "localhost";  
  13.     private int serverPort = 4444;  
  14.     private String browserCommand = "googlechrome";  
  15.     private String url = "http://www.google.com.hk";  
  16.       
  17.     private GooglePage page;  
  18.     private GoogleResultPage resultPage;  
  19.     private Selenium selenium;  
  20.     private Oat oat;  
  21.   
  22.     @Before  
  23.     public void setUp() throws Exception {  
  24.         // 初始化selenium  
  25.         selenium = new DefaultSelenium(serverUrl,serverPort,browserCommand, url);  
  26.         // Oat类是框架总的控制器,设置Selenium为背后的驱动  
  27.         oat = Oat.getInstance(selenium);  
  28.         oat.start();  
  29.         oat.open("/webhp");  
  30.         // 初始化被测试页面  
  31.         page = (GooglePage) oat.getPage(GooglePage.class);  
  32.         resultPage = (GoogleResultPage) oat.getPage(GoogleResultPage.class);  
  33.   
  34.     }  
  35.       
  36.     @Test  
  37.     public void testSearch() throws InterruptedException {  
  38.         // 在google页面收入"oat"进行搜索  
  39.                 page.doSearch("oat");         
  40.         page.waitToLoad(2000);  
  41.         // 在结构页面进行验证  
  42.         boolean result = resultPage.isTextPresent("oat");  
  43.         Assert.assertTrue("Text oat is present", result);  
  44.     }  
  45.   
  46.     @After  
  47.     public void tearDown() throws Exception {  
  48.         oat.stop();  
  49.         oat = null;  
  50.         page = null;  
  51.         selenium = null;  
  52.     }  
  53.   
  54. }  

Oat.getInstance(Object engine):用于获取真正的Driver:

  1. //可以根据传入的不同engine,实例化不同的Vendor  
  2. public static Oat getInstance(Object engine) {  
  3.         if(instance == null) {  
  4.             synchronized(Oat.class) {  
  5.                 if(instance == null) {  
  6.                       
  7.                     String vendorTypeStr = getVendorTypeStr();  
  8.                       
  9.                     try {  
  10.                         Class<?> vendorType = Class.forName(vendorTypeStr);  
  11.                         Vendor vendor = getVendor(vendorType, engine);                
  12.                         instance = new Oat();  
  13.                         instance.vendor = vendor;  
  14.                           
  15.                     } catch (ClassNotFoundException e) {  
  16.                         throw new RuntimeException("Not Found vendor " + vendorTypeStr, e);  
  17.                     }   
  18.                 }  
  19.             }  
  20.         }  
  21.           
  22.         return instance;  
  23.     }  

Oat.getPage()方法详解

  1. public Page getPage(Class<? extends Page> pageType) {  
  2.         Page page = null;  
  3.           
  4.         page = initialize(pageType);  
  5.         page.setVendor(vendor);  
  6.           
  7.     }  
  8.   
  9. private Page initialize(Class<? extends Page> pageType) {  
  10.                 //读取page类中的annotation  
  11.         OatPage anno = pageType.getAnnotation(OatPage.class);  
  12.           
  13.         if(anno == null) {  
  14.             throw new RuntimeException("Please add com.perficient.oat.component.annotaion.OatPage annotation in Page class!");  
  15.         }  
  16.           
  17.         Page page = null;  
  18.         try {  
  19.             page = pageType.newInstance();  
  20.         } catch (Exception e) {  
  21.             throw new RuntimeException("Page Class must have a non-parameter constructor.", e);  
  22.         }   
  23.           
  24.         Class<?> tempType = pageType;  
  25.           
  26.         while(tempType != null) {  
  27.             Field[] fields = tempType.getDeclaredFields();  
  28.               
  29.             for(Field field : fields ) {  
  30.                   
  31.                 com.perficient.oat.component.annotaion.Element annotation =   
  32.                     field.getAnnotation(com.perficient.oat.component.annotaion.Element.class);  
  33.                   
  34.                 if(annotation == null) {  
  35.                     continue;  
  36.                 }  
  37.                   
  38.                 Class<?> fieldClazz = field.getType();  
  39.                 // 只处理Element的子类  
  40.                 Class<? extends Element> elementClazz = fieldClazz.asSubclass(Element.class);  
  41.                   
  42.                 String locator = annotation.value();  
  43.                   
  44.                 field.setAccessible(true);  
  45.                                 //使用反射初始化Page类的各个Element子类,并赋予Locator值  
  46.                   
  47.                 try {  
  48.                     field.set(page, getElement(elementClazz, locator));  
  49.                 } catch (Exception e) {  
  50.                     throw new RuntimeException("set Element " + field.getName() + " error", e);  
  51.                 }  
  52.             }  
  53.               
  54.             tempType = tempType.getSuperclass();  
  55.         }  
  56.           
  57.         return page;  
  58.           
  59.     }  
  60. //用于初始化Page类中的各个Element子类  
  61. private Element getElement(Class<? extends Element> elementType, String locator) {  
  62.         Element element = null;  
  63.         try {  
  64.             element = elementType.newInstance();  
  65.             element.setLocator(locator);  
  66.             element.setVendor(vendor);  
  67.         } catch (Exception e) {  
  68.             throw new RuntimeException(e);  
  69.         }   
  70.         return element;  
  71.     }  

以上就是一个完整的基于Selenium driver的框架实现.以下是我们的Vendor接口:

  1. public interface Vendor {  
  2.       
  3.     public void start();  
  4.     public void stop();  
  5.     public void open(String url);  
  6.     public void openWindow(String url, String windowId);  
  7.     public void type(String locator, String value);  
  8.     public void check(String locator);  
  9.     public void uncheck(String locator);  
  10.     public boolean isChecked(String locator);  
  11.     public boolean isEditable(String locator);  
  12.     public void select(String selectLocator, String optionLocator);  
  13.     public String getSelectedLabel(String locator);  
  14.     public String[] getSelectedLabels(String locator);  
  15.     public boolean isSelected(String label);  
  16.     public void submit(String formLocator);  
  17.     public void click(String locator);  
  18.     public boolean isTextPresent(String pattern);  
  19.     public boolean isElementPresent(String locator);  
  20.     public void waitForPageToLoad(String timeout);  
  21.     public void windowFocus(String windowId);  
  22.     public String getAttribute(String attributeLocator);  
  23.     public String getTableCellValue(String locator, int row, int col);  
  24.     public void waitForElementToLoad(String locator, String timeout);  
  25.     public String getLocation();  
  26. }  

 以下是seleniumVendor的实现:

  1. public class SeleniumVendor extends VendorTemplate<Selenium> {  
  2.   
  3.     @Override  
  4.     protected Selenium createEngine(VendorAttribute attribute) {  
  5.         return new DefaultSelenium(  
  6.                 attribute.getHost(),   
  7.                 attribute.getPort(),  
  8.                 attribute.getBrowser(),  
  9.                 attribute.getUrl());  
  10.     }  
  11.       
  12.     @Override  
  13.     public boolean isTextPresent(String pattern) {  
  14.         return engine.isTextPresent(pattern);  
  15.     }  
  16.   
  17.     @Override  
  18.     public void open(String url) {  
  19.         engine.open(url);  
  20.           
  21.     }  
  22.   
  23.     @Override  
  24.     public void select(String selectLocator, String optionLocator) {  
  25.         engine.select(selectLocator, optionLocator);  
  26.     }  
  27.   
  28.     @Override  
  29.     public void start() {  
  30.         engine.start();  
  31.     }  
  32.   
  33.     @Override  
  34.     public void stop() {  
  35.         engine.stop();  
  36.     }  
  37.   
  38.     @Override  
  39.     public void submit(String formLocator) {  
  40.         engine.submit(formLocator);  
  41.           
  42.     }  
  43.   
  44.     @Override  
  45.     public void type(String locator, String value) {  
  46.         engine.type(locator, value);  
  47.     }  
  48.   
  49.     @Override  
  50.     public void click(String locator) {  
  51.         engine.click(locator);  
  52.           
  53.     }  
  54.   
  55.     @Override  
  56.     public void waitForPageToLoad(String timeout) {  
  57.         engine.waitForPageToLoad(timeout);  
  58.           
  59.     }  
  60.   
  61.     @Override  
  62.     public void windowFocus(String windowId) {  
  63.         engine.selectWindow(windowId);  
  64.         engine.windowFocus();  
  65.     }  
  66.   
  67.     @Override  
  68.     public void openWindow(String url, String windowId) {  
  69.         engine.openWindow(url, windowId);  
  70.     }  
  71.   
  72.     @Override  
  73.     public void check(String locator) {  
  74.         engine.check(locator);  
  75.           
  76.     }  
  77.   
  78.     @Override  
  79.     public String getAttribute(String attributeLocator) {  
  80.         return engine.getAttribute(attributeLocator);  
  81.     }  
  82.   
  83.     @Override  
  84.     public boolean isElementPresent(String locator) {  
  85.         return engine.isElementPresent(locator);  
  86.     }  
  87.   
  88.     @Override  
  89.     public void uncheck(String locator) {  
  90.         engine.uncheck(locator);  
  91.           
  92.     }  
  93.   
  94.     @Override  
  95.     public boolean isChecked(String locator) {  
  96.         return engine.isChecked(locator);  
  97.     }  
  98.   
  99.     @Override  
  100.     public String getSelectedLabel(String locator) {  
  101.         return engine.getSelectedLabel(locator);  
  102.     }  
  103.   
  104.     @Override  
  105.     public String[] getSelectedLabels(String locator) {  
  106.         return engine.getSelectedLabels(locator);  
  107.     }  
  108.   
  109.     @Override  
  110.     public boolean isSelected(String label) {  
  111.         return engine.isSomethingSelected(label);  
  112.     }  
  113.   
  114.     @Override  
  115.     public boolean isEditable(String locator) {  
  116.         return engine.isEditable(locator);  
  117.     }  
  118.   
  119.     @Override  
  120.     public String getTableCellValue(String locator, int row, int col) {  
  121.         return engine.getTable(locator + "." + String.valueOf(row)+ "." +String.valueOf(col));  
  122.     }  
  123.   
  124.     @Override  
  125.     public void waitForElementToLoad(String locator, String timeout) {  
  126.         String script = "selenium.isElementPresent(\"" + locator + "\")";  
  127.         engine.waitForCondition(script, timeout);  
  128.     }  
  129.   
  130.     @Override  
  131.     public String getLocation() {  
  132.         return engine.getLocation();  
  133.     }  
  134.   
  135.   
  136. }  

如果我们需要改成其他Dirver,新建立一个Vendor的实现类即可

最后我邀请你进入我们的【软件测试学习交流群:785128166】, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路

作为一个软件测试的过来人,我想尽自己最大的努力,帮助每一个伙伴都能顺利找到工作。所以我整理了下面这份资源,现在免费分享给大家,有需要的小伙伴可以关注【公众号:程序员二黑】自提!

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

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

相关文章

口才教育:如何提升沟通技巧与表达能力

口才教育&#xff1a;如何提升沟通技巧与表达能力 口才教育在现代社会中扮演着越来越重要的角色。拥有良好的沟通技巧和表达能力对于个人的职业发展、人际交往乃至生活质量都至关重要。因此&#xff0c;如何有效地提升口才能力成为了许多人关注的焦点。本文将探讨口才教育的重…

java-可变参数

可变参数是什么&#xff1f; 可变参数就是指传入的参数个数是可变的&#xff0c;不是固定的 为什么要可变参数&#xff1f; 当我们要传入大量的形参时&#xff0c;我们就可以用到可变参数了 定义格式 数据类型...变量名; 例如int ...a; 可变参数的细节&#xff1a; &…

Vue2(五):收集表单数据、过滤器、内置指令和自定义指令

一、回顾 总结Vue监视数据 1.Vue监视数据的原理&#xff1a; 1.vue会监视data中所有层次的数据。 2.如何监测对象中的数据?通过setter实现监视&#xff0c;且要在new Vue时就传入要监测的数据。(1&#xff09;.对象中后追加的属性&#xff0c;Vue默认不做响应式处理(2&#…

java拷贝数组

package com.mohuanan.exercise;public class Exercise {public static void main(String[] args) {int[] arr {1, 2, 3, 4, 5, 6, 7, 8, 8}; //格式化快捷键 CTRL 加 Alt 加 L键// F1截图 F3贴图//调用 copyOfRangeint[] ints copyOfRange(arr, 3, 7);for (int i 0; i &l…

学习网络编程No.13【网络层IP协议理解】

引言&#xff1a; 北京时间&#xff1a;2024/3/5/8:38&#xff0c;早六加早八又是生不如死的一天&#xff0c;不过好在喝两口热水提口气手指还能跳动。当然起关键性作用的还是思维跟上了课程脑袋较为清晰&#xff0c;假如是听学校老师在哪里磨过来磨过去&#xff0c;那我倒头就…

三、HarmonyOS 应用开发入门之运行Hello World

目录 1、课程对象 1.1、有移动端开发经验 1.2、无移动端开发经验 1.3、对 HarmonyOS 感兴趣 2、DevEco Studio 的使用 2.1、DevEco Studio 的关键特性 智能代码编辑 低代码开发 多段双向实时预览 多端模拟仿真 2.2、安装配置 DevEco Studio 2.2.1、官网开发工具下载地…

Vue-Vben-Admin:中大型项目后台解决方案及如何实现页面反向传值

Vue-Vben-Admin&#xff1a;中大型项目后台解决方案及如何实现页面反向传值 摘要&#xff1a; Vue-Vben-Admin是一个基于Vue3.0、Vite、Ant-Design-Vue和TypeScript的开源项目&#xff0c;旨在为开发中大型项目提供一站式的解决方案。它涵盖了组件封装、实用工具、钩子函数、动…

Arduino ESP8266 SSD1306 硬件I2C+LittleFS存储GBK字库实现中文显示

Arduino ESP8266 SSD1306 硬件I2C+LittleFS存储GBK字库实现中文显示 📍相关篇《Arduino esp8266 软件I2C SSD1306 +LittleFS存储GBK字库实现中文显示》 🌼显示效果: ✨将部分函数重构,和上面相关篇的软件I2C通讯相关接口函数移植过来,除了汉字显示采用自己写的API函数外…

【数据结构取经之路】快速排序的非递归实现

概述 递归实现快速排序在一些场景下有栈溢出的风险&#xff0c;下面就谈谈如何用非递归的方法实现快速排序。 非递归实现的思想 递归实现与非递归实现快速排序的本质是一致的&#xff0c;效率并不会因为用了非递归实现而有所提升。递归实现快速排序的本质就在于通过递归&…

Linux系统目录结构详细介绍

目录 一、根目录&#xff08;/&#xff09; 二、/bin 三、/boot 四、/dev 1.设备文件类型&#xff1a; 2.常见设备文件&#xff1a; 五、/etc 六、/home 七、/root 八、/run 九、/sbin 十、 /tmp 十一、/usr 十二、/var Linux系统目录结构是一种层次化的文件系…

【数据结构】Set的使用

文章目录 一、Set的使用1.Set的常用方法&#xff1a;1.boolean add(E e)2.void clear()3.boolean contains(Object o)4.boolean remove(Object o)5.int size()6.boolean isEmpty()7.Object[] toArray()8.boolean containsAll(Collection<?> c)9.boolean addAll(Collecti…

leetcode 热题 100_删除链表的倒数第 N 个结点

题解一&#xff1a; 递归&#xff1a;利用递归栈逆向遍历链表&#xff0c;并用全局变量记录当前遍历的是倒数第几位节点&#xff0c;当遍历到待删节点的上一位节点时&#xff0c;node.nextnode.next.next删除待删节点。需要注意当删除的是头节点时&#xff0c;直接return head.…

zabbix 7.0编译部署教程

zabbix 7.0编译部署教程 2024-03-08 16:50乐维社区 zabbix7.0 alpha版本、beta版本已经陆续发布&#xff0c;Zabbix7.0 LTS版本发布时间也越来越近。据了解&#xff0c;新的版本在性能提升、架构优化等新功能方面有非常亮眼的表现&#xff0c;不少小伙伴对此也已经跃跃欲试。心…

Visual Basic6.0零基础教学(3)—焦点概念和深入学习属性

焦点概念和深入学习属性 文章目录 焦点概念和深入学习属性前言一、什么是焦点(Focus)?焦点的特点 二、窗体属性一、窗体的结构二、窗体的属性三、事件四、方法 一.控件属性一. 标签 Label二.文本框 TextBox2.常用事件 三.命令按钮事件 总结 前言 今天我们来继续学习VB中的属性…

【漏洞复现】大华智慧园区综合管理平台 /carQuery/getNewStaypointDetailQuerySQL注入漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

基于Springboot的面向智慧教育的实习实践系统设计与实现(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的面向智慧教育的实习实践系统设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&…

ChatGPT提问技巧:受控生成提示

ChatGPT提问技巧&#xff1a;受控生成提示 受控生成提示是一种可以高度控制输出结果的文本生成技术。 具体做法是为模型提供一组特定的输入&#xff0c;如模板、特定词汇或一组约束&#xff0c;用于指导生成过程。 通过为模型提供一组可用于指导生成过程的特定输入&#xff…

Mybatis Plus + Spring 分包配置 ClickHouse 和 Mysql 双数据源

目录 一、背景 二、各个配置文件总览&#xff08;文件位置因人而异&#xff09; 2.1 DataSourceConfig 2.2 MybatisClickHouseConfig &#xff08;ClickHouse 配置类&#xff09; 2.3 MybatisMysqlConfig&#xff08;Mysql 配置类&#xff09; 2.4 application.propertie…

C语言例2-3:从键盘输入一个正整数(位数小于或等于10),判断其是否是回文数

回文数是将自然数n的各位数字反向排列得到自然数n1&#xff0c;若n1与n相等&#xff0c;则称为回文数&#xff0c;例如12321 //从键盘输入一个正整数&#xff08;位数小于或等于10&#xff09;&#xff0c;判断其是否是回文数 //回文数是将自然数n的各位数字反向排列得到自然数…

Skywalking(9.7.0) 告警配置

图片被吞&#xff0c;来这里看吧&#xff1a;https://juejin.cn/post/7344567669893021736 过年前一天发版&#xff0c;大家高高兴兴准备回家过年去了。这时候老板说了一句&#xff0c;记得带上电脑&#xff0c;关注用户反馈。有紧急问题在高速上都得给我找个服务区改好。 但是…