【问题标题】:Execution flow in selenium browser automationselenium 浏览器自动化中的执行流程
【发布时间】:2019-06-17 22:20:15
【问题描述】:

我不确定 selenium 中的脚本(自动测试)执行。 我想过程如下:

  • 开始执行。
  • 将 selenese 命令转换为 HTTP 请求。
  • 浏览器驱动的HTTP服务器接收到HTTP请求。
  • 浏览器驱动程序确定实施
    所需的步骤 命令。
  • 浏览器驱动程序在浏览器上执行它们。
  • 执行状态回传给浏览器的HTTP服务器 驱动程序,然后到脚本(IDE)。

我想这就是过程。有错误的地方请指正。

【问题讨论】:

    标签: selenium testing automation webdriver automated-tests


    【解决方案1】:

    是的,大体上就是这样。

    理论

    粗体和方框内是执行方,斜体和箭头表示使用的协议。

    当你想与浏览器交互时,

    1. 您的代码使用您使用的语言(Java、Python、Ruby 等)的webdriver 客户端(通常是库,如selenium) )。
    2. 该客户端与 webdriver 服务器 通信,按照 webdriver 协议 发送和接收数据;该协议封装在 http 中,以便于传输和控制。
    3. webdriver 服务器 将其转换为 浏览器 的实际命令 - 因此它(浏览器)与页面交互,或从中获取数据。

    流程始终是端到端的(例如,浏览器从不直接与您的代码通信:)),并且是双向的。失败/异常通常只会出现在您的代码的上游。


    一些细节

    该图中的“browser's webdriver”是二进制(程序) - Firefox 的“geckodriver”(在 Windows 上带有“.exe” )、“chromedriver”、“safaridriver”、“edgedriver.exe”(总是与“.exe”一起使用:))。它充当代理 - 一方面接受和理解 webdriver 协议中的命令,另一方面 - 知道如何与浏览器通信。

    webdriver 始终是 HTTP 服务器 - 所有命令都封装在 HTTP 中,使用常用方法 get/post/delete/put (关闭,如果与常规 REST 不同)。它implements the webdriver protocol,所以客户端(selenium & co)有一个定义良好的 API 来与之通信。因此它也可以称为“webdriver 服务器”——它侦听命令,将它们代理到浏览器,并将响应返回给客户端。 (没有人这样称呼它:),但它更容易区分“webdriver the executable”和“webdriver the protocol”)

    作为服务器,它在随机网络端口上绑定和侦听 - 在您的本地计算机或远程计算机上。如果您在本地运行,这就是它的二进制文件必须在您的 path 变量中的原因 - 在初始化时 Selenium 启动它(因此它必须能够找到它)并获取它正在侦听的网络端口 (对于进一步沟通)。如果您使用远程连接,您必须 a) 知道远程 webdriver 服务器的 IP:端口,或 b) 使用“Selenium Hub”,它在其域下跟踪此信息,并与您共享。


    webdriver 服务器和浏览器之间的通信通常是二进制 rpc,并且非常特定于浏览器 - 它使用内部 API,webdriver 知道如何最好地控制这个特定的浏览器。因此,驱动程序由浏览器供应商提供。这始终是本地(在同一台机器/操作系统中) 通信(至少据我所知)。


    如果您使用的是更高级别的框架,如 Robot Framework、Cucumber、JBehave 等,它位于该图中的“您的代码”之前,试图保护您免受某些 selenium 调用的影响。


    实践中

    “一张图抵千言”,那么代码一定是740之类的吧? :) 足够的理论,这是一个实际的例子:

    from selenium import webdriver       # importing selenium bindings
    
    wd = webdriver.Firefox()      # connect to the "webdriver server", a local one
    element = wd.find_element_by_css_selector('#my-id')  # locate an element
    the_text = element.text        # get is text
    
    assert(text == 'My awesome text!')   # verify it's the expected one
    

    整个清单是第一部分中的您的代码 - 为完成工作而执行的不同指令、流程控制和检查。在第 1 行,python 的 selenium 库被导入以供进一步使用。

    Selenium是最流行的实现webdriver协议的框架;它具有不同语言的实现(即绑定) - python 这里,javarubyjavascript 等等。它努力做的是为所有这些提供一个统一的接口——Java 中的getText() 也可以在 Python 中作为.text 使用,等等。通过这个接口,它将客户端与实际的 webdriver 协议隔离开来——用户输入.text,并且不关心它是如何实际执行的,也不必在协议发生变化时更改他的代码。


    第 3 行,实例化了 webdriver 对象;因为这里是一个本地服务器,所以实例化过程通过前面描述的本地步骤——“webdriver 服务器”运行,它的端口现在是已知的(并存储在对象中),并且可以进行通信开始。


    代码中的

    第 4 行 使用selenium 方法来定位页面中的特定元素。在后台,该库向 webdriver 服务器发送一个 POST http 请求,以定位该元素。
    为什么发布?因为一旦成功找到,服务端就会给它分配一个内部id,以后会用到;并将 id 返回给客户端,客户端将其存储为 element 对象的属性(*参见脚注)
    webdriver 服务器如何定位该元素?不怎么 - 它通过专有协议与浏览器通信,说“嘿,使用你的渲染和评估引擎,在 DOM 中找到一个与这个 CSS 选择器匹配的元素,并给我一个我们将来可以重用的参考。 " (即“魔法”:)。所以是浏览器完成工作,webdriver 服务器只是代理通信。


    让我们进入细节 - 第 5 行 执行命令.text,显然返回元素的文本 (如果你不懂 python,不要惊慌为什么它是一个命令,但末尾没有 () - 这是一个语言怪癖,将方法别名为对象属性,一个非常方便的功能)
    此时会发生什么: selenium python binding 将此命令与其公共接口中的getElementText 匹配;然后它将它与webdriver protocol command 匹配(打开链接,这很有趣,我保证) - 它是 GET 类型,它的参数是这个和那个。
    它打开到“localhost:the_know_port”的网络连接,到这个端点:

    GET /session/2cce72b7-c748-48bc-b350-6dd6730b5a69/element/5/text
    

    第一个“随机”字符串是会话 id - 一个 webdriver 服务器可以被许多客户端使用,你的服务器在第 3 行建立并存储。第二个参数 (“5”) 是元素的 id,在第 4 行建立。然后是“文本” - 您请求的子资源,元素支持的子资源之一。
    这就是臭名昭著的 webdriver 协议/API——特定访问方案的知识(您可以在会话中获取已建立元素的“文本”)和流(您必须首先建立一个共享会话,然后是一个元素的引用,所以最终得到“文本”)

    之后,webdriver 服务器让浏览器从其 DOM ("the magic") 中获取信息,并通过网络将其发送回客户端(selenium 实例):

    {"sessionId":"2cce72b7-c748-48bc-b350-6dd6730b5a69","status":0,"value":"My awesome text!"}
    

    您的 selenium 实例正在等待响应,从负载中获取并解析信息,并将值返回给您的代码 - 变量 the_text 现在具有值“我的真棒文本!”。


    并且 - 完成,循环 code -> webdriver client -> webdriver server -> browser -> webdriver server -> webdriver client -> code 现在完成了。


    脚注:

    (*) - 这就是可怕的StaleElementReferenceException 的真正原因:所有三个 - 客户端、webdriver 服务器和浏览器都持有对 DOM 中元素的引用。
    但是在某个特定的时刻,第 3 方 - 在浏览器中运行的 javascript 代码,更改/删除了元素,幸福地没有意识到某些东西有一个引用,它现在使 无效(想想看,这是一个非常邪恶的行为: D).
    下次客户端尝试通过 webdriver 服务器在浏览器中与引用交互时 - 元素不再存在。自然,交互失败,失败返回到客户端并出现异常;它的文本消息是“元素不再附加到 DOM”——希望这有点神秘现在很有意义。

    【讨论】:

    • 您说的是“浏览器的网络驱动程序”。我没明白。你能详细说明一下吗?
    • 我已经提到浏览器驱动的HTTP服务器接收HTTP请求。您提到 WebDriver 始终是 HTTP 服务器。我也不明白这部分。请在这里阐明一下。
    • 如果您提供一个描述命令执行的端到端示例可能会很棒,因为外行术语没有明确的解释。也许是一个简单的,比如 'driver.get("facebook.com");'。
    • @learningQA - 更新;相当多:D。说实话,这开始是作为评论“是的,就是这样,这样那样”,在第 400 个字符决定移动作为答案,现在是一篇文章 :) 希望它有所帮助。
    • 我觉得这应该是一个硒脚本执行流程的wiki。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 2017-10-28
    • 2020-03-13
    • 1970-01-01
    • 2016-06-04
    相关资源
    最近更新 更多