1. 背景介绍

目前互联网企业在 UI 自动化测试上的投入不断减少,原因有下:

  • UI 自动化测试十分不稳定,很容易受到其它因素影响
  • 投入的性价比不高,在如今 APP 高速迭代的情况下,维护 UI 自动化的成本十分大
  • 现在很多逻辑都放在了后端 API 端,可以通过接口自动化覆盖大部分场景

那为何还要花精力去学习 UI 自动化测试,原因也有下:

  • 即使将后端接口测试覆盖的很全,但也难以站在一个用户的思维视角去体验产品,还是可能会存在场景未考虑到
  • UI 自动化测试投入的越来越少,不代表不投入了,接口自动化和 UI 自动化并不冲突

综上,如今 UI 自动化的使用场景不再是去覆盖所有 UI 场景的用例,而是在将接口自动化最好的基础上,挑选核心的 UI 自动化场景用例进行覆盖。

2. Seleninum 介绍

2.1 Seleninum 介绍

官网:https://www.selenium.dev/

Selenium 它是一个支持多语言、多平台、多浏览器的 Web 自动化测试框架,最初是由 ThoughtWorks 公司一个叫 JasonR.Huggins 的工程师和他的团队开发出来。

Selenium 直接运行在浏览器中,就像真正的用户在操作一样,常用于测试与浏览器的兼容性、以及系统回归测试,检验软件功能和用户需求。

2.2 Seleninum 特点

Selenium 是免费的、开源的,更准确来说,Selenium 不是一个工具,它是一系列工具的总称。

并且 Selenium 支持多种编程语言、支持多种浏览器、且可以运行在多个平台上。

2.3 Selenium 框架组成

selenium + python 中文文档:https://python-selenium-zh.readthedocs.io/zh\_CN/latest/

Selenium 主要包括四个工具:

  • Selenium IDE(火狐的一个插件,可以快速的实现录制和回放脚本)
  • Selenium RC(Selenium1.0 的核心,实现对浏览器的控制但是有很多限制,最新版本已废弃)
  • Selenium Webdriver(Selenium2.0 以后的核心,用于控制浏览器)
  • Selenium Grid(支持脚本在多台机器上并行执行脚本,提升执行效率)

Selenium3.0 之后,最核心的就是下面的这两个工具:

  • Selenium Webdriver
  • Selenium Grid

WebDriver 框架原理

WebDriver 是一个用于自动化浏览器操作的工具集,其架构设计遵循客户端 - 服务器模型:

  • 客户端:通常是使用某种编程语言(如 Python、Java、C# 等)编写的测试脚本。客户端代码通过 WebDriver API 向浏览器驱动程序发送命令,请求执行特定的操作,比如打开网页、点击按钮、输入文本等。
  • 服务器(浏览器驱动程序):每个主流浏览器(如 Chrome、Firefox、Safari 等)都有对应的浏览器驱动程序(如 ChromeDriver、GeckoDriver、SafariDriver 等)。这些驱动程序充当服务器的角色,接收来自客户端的命令,并将其转换为浏览器能够理解的操作。浏览器驱动程序与对应的浏览器进行通信,控制浏览器执行相应的动作,并将执行结果返回给客户端。

2.4 Selenium 发展历程

2.4.1 Selenium 1.0 核心原理

Selenium 1.0,又称 Selenium RC,其中 RC 是 Remote Control 的缩写。Selenium RC 利用的原理是:JavaScript 代码可以很方便地获取页面上的任何元素并执行各种操作。

2.4.2 Selenium 2.0 和 3.0 核心原理

Selenium 2.0,又称 Selenium WebDriver,它利用的原理是:使用浏览器原生的 WebDriver 实现页面操作。它 的实现方式完全不同于 Selenium 1.0。并且 Selenium WebDriver 是典型的 Server-Client 模式,Server 端就是 Remote Server。

V3.0 相比 V2.0 并没有本质上的变化,主要是增加了对 MacOS 的 Safari 和 Windows 的 Edge 的支持,并彻底删除了对 Selenium RC 的支持。

3. Selenium 快速上手

3.1 环境搭建

3.1.1 在 Cmd 终端安装 Selenium

1
pip install selenium

3.1.2 下载 Chrome Selenium 驱动(以 Chrome 浏览器为例)

  • 查看 Chrome 浏览器版本

注意:如果发现代码运行时突然报错,则可以排查一下是否是因为浏览器版本与驱动版本不匹配

  • 下载 chromedriver 驱动(需要与本地浏览器版本相对应,前三位一定要一样,第四位可以选最接近的)

Tips

如果你不确定你的 Mac 电脑是 arm 架构还是 x86 架构,则可以复制这条指令到终端执行一下,就能显示出是电脑哪一个架构:uname -m

  • 安装 chromedriver 驱动
    • Mac:将解压后的 chromedriver 移动到 /usr/local/bin 目录下
    • Windows:将解压后的 chromedriver.exe 放到 python.exe 的同级目录下,确保这个路径在环境变量中

Tips

系统会先在本地目录寻找是否存在 chromedriver 这个文件,然后才会到上面的目录去寻找。

3.1.3 导入 Selenium 包

1
from selenium import webdriver

3.2 Hello World

在进行完上述的环境搭建步骤后,可以先来上手写一个简单的用例,看看执行的效果是什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 1.申请一个浏览器驱动实例
driver = webdriver.Chrome()

# 2.打开访问页面
driver.get("http://www.baidu.com")

# 3.等待一段时间,确保页面已经显示出来再进行下一步操作
time.sleep(2)

# 4.通过 CSS 选择器定位元素,输入 python 文本
element = driver.find_element(By.CSS_SELECTOR, "input#kw")
element.send_keys("python")

# 5.通过 ID 定位元素,点击搜索按钮
click_element = driver.find_element(By.ID, "su")
click_element.click()

# 6.等待一段时间,确保页面已经显示出来再进行下一步操作,并将标题打印出来
time.sleep(2)
print(driver.title)

# 7.进行断言操作
assert 'python' in driver.title

# 8.释放掉这个浏览器驱动实例
# driver.close()
driver.quit()

Tips:close() 和 quit() 方法的区别

  • close() 方法只会关闭浏览器窗口
  • quit() 方法不仅会关闭浏览器窗口,还会退出后台的驱动实例

因此我们更建议使用 quit() 方法来释放实例。

执行上面这条用例可以发现,点击执行后会自动弹起浏览器的页面,系统在自动进行代码里规定的操作。从浏览器的左上角也可以看到一行字,显示 “Chrome 正受到自动测试软件的控制 “。

3.3 调用链路

通过上面的案例可以总结出 Selenium 的调用链路主要分为三个部分:

  • 先通过各种编程语言调用 selenium 库里的 API 编写出脚本
  • 根据脚本里调用的 API 与 driver 驱动进行通讯
  • driver 驱动再通过浏览器模拟出脚本里实现的步骤

因此 driver 其实充当的是一个代理层,脚本不会直接去控制浏览器的运行,而是通过 driver 去操作浏览器。

4. Selenium IDE

4.1 介绍

Selenium IDE 是一款 Selenium 脚本录制工具(仅作为入门使用),目前 Selenium-IDE 不仅支持 FireFox,还支持 Chrome。

4.2 下载方式

Chrome 插件下载:https://www.crx4chrome.com/crx/77585/

Firefox 插件下载:https://addons.mozilla.org/en-US/firefox/addon/selenium-ide/

4.3 使用方法

  1. 打开下载好的插件,点击新建一个项目。

  2. 输入要录制的地址,然后开始录制

  3. 关掉网址页面,然后点击右上角停止录制

  4. 点击回放刚刚的录制情况

  5. 导出成代码脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Generated by Selenium IDE
import pytest
import time
import json
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

class TestTestbaidu():
def setup_method(self, method):
self.driver = webdriver.Chrome()
self.vars = {}

def teardown_method(self, method):
self.driver.quit()

def test_testbaidu(self):
self.driver.get("https://www.baidu.com/")
self.driver.set_window_size(1728, 997)
self.driver.find_element(By.ID, "kw").click()
self.driver.find_element(By.ID, "kw").send_keys("python")
self.driver.find_element(By.ID, "su").click()
self.driver.find_element(By.ID, "wrapper_wrapper").click()
self.driver.close()