做过两年自动化测试的小伙伴说web自动化测试真的不难,无非就是一些浏览器操作,页面元素操作,常规的情况很容易处理,再学一学特殊元素的处理,基本就能应付项目的测试了。

  这个话倒没错,但是真正要学好自动化测试,深入自动化,并不是那么简单。首先你得懂原理吧,原理不懂,你就不知道怎么解决一些异常情况,也无法完成拓展。其次你得学会写自己的测试框架吧,一个项目写了100个测试类,都是零散的脚本,没有任何设计而言,都是纯粹的业务代码,那我可以说,换了项目你这些脚本就成了垃圾,因此,我们要做自动化,要成为自动化大牛,就一定要花时间去要搞清楚自动化实现的原理,并且学会自己去实现自动化测试框架,乃至于自动化测试平台。

  下面一段代码实现了一个很简单的功能:

  1.打开浏览器

  2.访问页面“http://ke.qq.com”

  3.定位到页面的搜索框

  4.输入查询数据

  5.定位搜索按钮

  6.点击搜索按钮,完成搜索

  代码如下图:

  

package web.demo;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.Test; public class Demo1 {
    @Test
    public void test(){
        //设置可执行的驱动文件路径
        System.setProperty("webdriver.gecko.driver", "src/test/resources/geckodriver.exe");
        //创建火狐驱动对象
        WebDriver driver = new FirefoxDriver();
        //访问腾讯课堂首页
        driver.get("https://ke.qq.com/");
        //定位页面的搜索框
        WebElement searchInputBox = driver.findElement(By.id("js_keyword"));
        //往搜索框输入数据
        searchInputBox.sendKeys("柠檬班");
        //定位到搜索按钮
        WebElement searchButton = driver.findElement(By.id("js_search"));
        //点击搜索
        searchButton.click();
    }
}
 

  驱动文件位置:

  

  

  需求很简单,代码也很简单。但是你知道代码中的这些浏览器操作,元素操作,是如何完成的吗?

  比如,浏览器启动完成后,再调用:driver.get("https://ke.qq.com/");就能在导航栏中访问到指定的这个页面,这个里面发生了什么,到底是客户端脚本直接操作浏览器还是通过某些中间件来完成??

  底层原理如下:

  1.在自动化测试过程中,存在三部分组件:客户端脚本+驱动+浏览器终端。

  2.驱动文件,以geckodriver.exe为例,这个可执行的驱动文件启动后,相当于一个暴露了一系列接口的服务器,监听某一端口,例如:89890。

  3.客户端的操作(访问页面,定位元素,输入数据,点击按钮等)都是封装成了接口请求(eg:/session/xx/yy),然后提交到驱动服务器。

  4.驱动服务器接收到客户端的请求后,再跟终端浏览器交互。

  5.终端浏览器做出相应操作。

    下图描述了整个交互过程:

  

  以定位元素为例,定位搜索框,我们来看底下这行代码在执行的时候底层到底经历了些什么:

WebElement searchInputBox = driver.findElement(By.id("js_keyword"));

  

实际,底层请求时,每个请求会被封装为一个command,然后根据不同的commannd封装得到不同的HttpRequest对象:

根据此命令,得到接口地址:

拿到此接口地址封装为一个HttpRequest请求。

client.execute(httpRequest,true),执行接口调用:

  至于其他操作:往输入框输入数据,点击按钮等,都是对应一个接口地址,通过调用接口,请求驱动来处理,最后驱动同浏览器进行交互,浏览器按照指示做出对应操作。

  Selenium有一个类AbstractHttpCommandCodec,此类中维护了众多自动化操作对应的接口地址:

  

public AbstractHttpCommandCodec() {
defineCommand(STATUS, get("/status")); defineCommand(GET_ALL_SESSIONS, get("/sessions"));
defineCommand(NEW_SESSION, post("/session"));
defineCommand(GET_CAPABILITIES, get("/session/:sessionId"));
defineCommand(QUIT, delete("/session/:sessionId")); defineCommand(GET_SESSION_LOGS, post("/logs"));
defineCommand(GET_LOG, post("/session/:sessionId/log"));
defineCommand(GET_AVAILABLE_LOG_TYPES, get("/session/:sessionId/log/types")); defineCommand(SWITCH_TO_FRAME, post("/session/:sessionId/frame"));
defineCommand(SWITCH_TO_PARENT_FRAME, post("/session/:sessionId/frame/parent")); defineCommand(CLOSE, delete("/session/:sessionId/window"));
defineCommand(SWITCH_TO_WINDOW, post("/session/:sessionId/window")); defineCommand(FULLSCREEN_CURRENT_WINDOW, post("/session/:sessionId/window/fullscreen")); defineCommand(GET_CURRENT_URL, get("/session/:sessionId/url"));
defineCommand(GET, post("/session/:sessionId/url"));
defineCommand(GO_BACK, post("/session/:sessionId/back"));
defineCommand(GO_FORWARD, post("/session/:sessionId/forward"));
defineCommand(REFRESH, post("/session/:sessionId/refresh")); defineCommand(SET_ALERT_CREDENTIALS, post("/session/:sessionId/alert/credentials")); defineCommand(UPLOAD_FILE, post("/session/:sessionId/file"));
defineCommand(SCREENSHOT, get("/session/:sessionId/screenshot"));
defineCommand(ELEMENT_SCREENSHOT, get("/session/:sessionId/screenshot/:id"));
defineCommand(GET_TITLE, get("/session/:sessionId/title")); defineCommand(FIND_ELEMENT, post("/session/:sessionId/element"));
defineCommand(FIND_ELEMENTS, post("/session/:sessionId/elements"));
defineCommand(GET_ELEMENT_PROPERTY, get("/session/:sessionId/element/:id/property/:name"));
defineCommand(CLICK_ELEMENT, post("/session/:sessionId/element/:id/click"));
defineCommand(CLEAR_ELEMENT, post("/session/:sessionId/element/:id/clear"));
defineCommand(
GET_ELEMENT_VALUE_OF_CSS_PROPERTY,
get("/session/:sessionId/element/:id/css/:propertyName"));
defineCommand(FIND_CHILD_ELEMENT, post("/session/:sessionId/element/:id/element"));
defineCommand(FIND_CHILD_ELEMENTS, post("/session/:sessionId/element/:id/elements"));
defineCommand(IS_ELEMENT_ENABLED, get("/session/:sessionId/element/:id/enabled"));
defineCommand(ELEMENT_EQUALS, get("/session/:sessionId/element/:id/equals/:other"));
defineCommand(GET_ELEMENT_RECT, get("/session/:sessionId/element/:id/rect"));
defineCommand(GET_ELEMENT_LOCATION, get("/session/:sessionId/element/:id/location"));
defineCommand(GET_ELEMENT_TAG_NAME, get("/session/:sessionId/element/:id/name"));
defineCommand(IS_ELEMENT_SELECTED, get("/session/:sessionId/element/:id/selected"));
defineCommand(GET_ELEMENT_SIZE, get("/session/:sessionId/element/:id/size"));
defineCommand(GET_ELEMENT_TEXT, get("/session/:sessionId/element/:id/text"));
defineCommand(SEND_KEYS_TO_ELEMENT, post("/session/:sessionId/element/:id/value")); defineCommand(GET_ALL_COOKIES, get("/session/:sessionId/cookie"));
defineCommand(GET_COOKIE, get("/session/:sessionId/cookie/:name"));
defineCommand(ADD_COOKIE, post("/session/:sessionId/cookie"));
defineCommand(DELETE_ALL_COOKIES, delete("/session/:sessionId/cookie"));
defineCommand(DELETE_COOKIE, delete("/session/:sessionId/cookie/:name")); defineCommand(SET_TIMEOUT, post("/session/:sessionId/timeouts"));
defineCommand(SET_SCRIPT_TIMEOUT, post("/session/:sessionId/timeouts/async_script"));
defineCommand(IMPLICITLY_WAIT, post("/session/:sessionId/timeouts/implicit_wait")); defineCommand(GET_APP_CACHE_STATUS, get("/session/:sessionId/application_cache/status"));
defineCommand(IS_BROWSER_ONLINE, get("/session/:sessionId/browser_connection"));
defineCommand(SET_BROWSER_ONLINE, post("/session/:sessionId/browser_connection"));
defineCommand(GET_LOCATION, get("/session/:sessionId/location"));
defineCommand(SET_LOCATION, post("/session/:sessionId/location")); defineCommand(GET_SCREEN_ORIENTATION, get("/session/:sessionId/orientation"));
defineCommand(SET_SCREEN_ORIENTATION, post("/session/:sessionId/orientation"));
defineCommand(GET_SCREEN_ROTATION, get("/session/:sessionId/rotation"));
defineCommand(SET_SCREEN_ROTATION, post("/session/:sessionId/rotation")); defineCommand(IME_GET_AVAILABLE_ENGINES, get("/session/:sessionId/ime/available_engines"));
defineCommand(IME_GET_ACTIVE_ENGINE, get("/session/:sessionId/ime/active_engine"));
defineCommand(IME_IS_ACTIVATED, get("/session/:sessionId/ime/activated"));
defineCommand(IME_DEACTIVATE, post("/session/:sessionId/ime/deactivate"));
defineCommand(IME_ACTIVATE_ENGINE, post("/session/:sessionId/ime/activate")); // Mobile Spec
defineCommand(GET_NETWORK_CONNECTION, get("/session/:sessionId/network_connection"));
defineCommand(SET_NETWORK_CONNECTION, post("/session/:sessionId/network_connection"));
defineCommand(SWITCH_TO_CONTEXT, post("/session/:sessionId/context"));
defineCommand(GET_CURRENT_CONTEXT_HANDLE, get("/session/:sessionId/context"));
defineCommand(GET_CONTEXT_HANDLES, get("/session/:sessionId/contexts"));
}

  另外,可能会有人好奇,驱动服务器是何时启动的服务。其实是在执行下面这行代码的时候启动的,大家可执行去debug调试selenium的底层代码:

  

//创建火狐驱动对象
WebDriver driver = new FirefoxDriver();

  当上面这行代码执行完,可以发现eclipse的控制台显示了如下信息:

1531911173760    geckodriver    INFO    geckodriver 0.19.0
1531911173772 geckodriver INFO Listening on 127.0.0.1:21984

  说明此驱动服务器成功启动了,并且监听了本机的21984端口,等待客户端发起请求,并处理。

  至于驱动跟浏览器之间是如何交互的,在后面的文章中会择机介绍,请大家守候。

web自动化原理揭秘的更多相关文章

  1. Selenium Web自动化 原理

    文章转自 白月黑羽教Python 原理 说到web应用自动化测试,第一选择就是 Selenium 框架. Selenium 是一个 Web 应用的自动化框架. 通过它,我们可以写出自动化程序像人一样( ...

  2. web自动化原理

    在说原理之前我想说下我所理解的selenium: (1).支持多语言,多平台,多浏览器 (2).它是一个工具包 (3).提供所有的网页操作api,是一个功能库 通过selenium来实现web自动化, ...

  3. 【Selenium01篇】python+selenium实现Web自动化:搭建环境,Selenium原理,定位元素以及浏览器常规操作!

    一.前言 最近问我自动化的人确实有点多,个人突发奇想:想从0开始讲解python+selenium实现Web自动化测试,请关注博客持续更新! 二.话不多说,直接开干,开始搭建自动化测试环境 这里以前在 ...

  4. Web自动化必会知识:「Web基础、元素定位、元素操作、Selenium运行原理、项目实战+框架」

    1.web 基础-html.dom 对象.js 基本语法 Dom 对象里面涉及元素定位以及对元素的修改.因为对元素操作当中涉及的一些 js 操作,js 基本语法要会用.得要掌握前端的基本用法.为什么要 ...

  5. web自动化工具-livereload

    web自动化工具-livereload livereload是一个很神奇的工具,主要解放了F5键,监听文件变动,整个页面自动刷新.可搭载gulp等构建工具使用.和liveStyle 针对样式文件相比, ...

  6. Web自动化之Headless Chrome测试框架集成

    使用Selenium操作headless chrome 推荐 简介 WebDriver是一个W3C标准, 定义了一套检查和控制用户代理(比如浏览器)的远程控制接口,各大主流浏览器来实现这些接口以便调用 ...

  7. Selenium Web 自动化

    1 Selenium Web 自动化 - Selenium(Java)环境搭建 2 Selenium Web 自动化 - 如何找到元素 3 Selenium Web 自动化 - Selenium常用A ...

  8. Airtest之web自动化(一)

    Airtest之web自动化(一) [此文档有许多涉及到gif动图的地方,请全屏观看]   了解Airtest: 简介: Airtest是由网易团队开发的一款自动化框架,前期运用与游戏测试(通过截图识 ...

  9. selenium的web自动化实战

    selenium自动化原理: 1.通过各种语言(python,java,ruby等)调用接口库 2.通过浏览器驱动(web driver)来驱动浏览器 利用Python自动化的环境安装: 1.pyth ...

随机推荐

  1. canvas制作随机验证码

    看到人家彩色背景的验证码想测试一下: 创建html代码: <canvas id="myCanvas" width="200" height="1 ...

  2. PAT——1005. 继续(3n+1)猜想

    pat原题目:https://www.patest.cn/contests/pat-b-practise/1005 原题目: 卡拉兹(Callatz)猜想已经在1001中给出了描述.在这个题目里,情况 ...

  3. 基于VC++的WinCE网口通信

    基于VC++的WinCE网口通信 WinCE下的网络编程与Windows下的非常类似,只是个别API函数有所不同.同样分为UDP和TCP两种,UDP就是无连接的通信,通过“用户数据报协议”(UDP)来 ...

  4. 一招搞定css页面布局

    如何做出漂亮的页面: 1. 多写页面,多改. 2. 多写页面,多改. 3. 多写页面,多改. 大致的思想步骤: 写页面的时候先规划好大致的分块,无论是用定位或者浮动,首先要确定要应用的场景,使用完浮动 ...

  5. javaSpring知识点总结

    1 js 概述 js是一门基于对象和事件驱动的脚本语言,主要应用在客户端 js特点: 交互性(信息的动态交互) 安全性(不允许直接访问本地硬盘) 跨平台(只要是可以解释js的浏览器都可以执行,和平台无 ...

  6. MongoTemplate复合条件查询

    分. 排序.按时间查询 Query query = new Query();        //必须条件        Criteria c = Criteria.where("VINID& ...

  7. RabbitMQ初学之踩坑记录

    1:账号或密码错误 com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused usi ...

  8. #leetcode刷题之路8-字符串转换整数 (atoi)

    请你来实现一个 atoi 函数,使其能将字符串转换成整数.首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止.当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面 ...

  9. 将图片写入二进制文件,再从二进制文件还原图片(c++)

    #include "string" #include "iostream" #include "fstream" using namespa ...

  10. What is a schema in a MySQL database?

    摘自:https://www.quora.com/What-is-a-schema-in-a-MySQL-database What is schema? In MySQL, physically, ...