web自动化测试工具Selenium的使用
2026/4/1 14:28:29 网站建设 项目流程

web自动化测试工具-Selenium

Selenium 是一个开源的 web 自动化测试工具,免费,主要做功能测试。

1.特点

  1. 开源

  2. 跨平台:linux、windows、mac

  3. 支持多种浏览器

  4. 支持多种语言

  5. 成熟稳定

  6. 功能强大

2.环境搭建

2.1.基于Python环境搭建

  1. Python开发环境

  2. 安装selenium包

# 安装 pip intsall selenium pip intsall selenium==2.48.0 ​ # 查看 pip show selenium ​ # 卸载 pip uninstall selenium
  1. 安装浏览器

  2. 安装浏览器驱动 – 保证能够用程序驱动浏览器,实现自动化。

# 安装地址 谷歌:chromedriver.storage.googleapis.com/index.html # 使用 将驱动目录路径添加到环境变量

3.webdriver使用

1.浏览器操作

from selenium import webdriver from time import sleep ​ # 打开谷歌 driver = webdriver.Chrome(); # 关闭 driver.quit() # 获取百度 driver.get('http://www.baidu.com') driver.maximize_window() # 最大化浏览器 driver.set_window_size(width=, height=) # 设置浏览器窗口大小 driver.set_window_position(x=,y=) # 设置浏览器窗口位置 driver.back() # 浏览器后退按钮 driver.forward() # 浏览器前进按钮 driver.refresh() # 刷新 driver.close() # 关闭当前窗口 driver.quit() # 关闭浏览器驱动对象 -- 关闭所有窗口 driver.title # 获取页面的title driver.current_url # 获取页面的url ​ ​ # 拉动滚动条,执行js语句 js = "window.scrollTo(左边距, 上边距)" # 单位px driver.execute_script(js) ​ ​ # 切换子窗口,当前页面无法访问子页面的元素,需要切换页面才能定位 driver.switch_to.frame(frame_reference=) # frame_reference 可以是frame看框架的name,id或者定位到frame元素 driver.switch_to.default_content() # 恢复默认页面 ​ ​ # 切换窗口 driver.current_window_handle # 获取当前窗口句柄 driver.window_handles # 获取所有窗口句柄 driver.switch_to.window(handle) # 切换指定句柄窗口 ​ handles = driver.window_handles for h in handles: if h != current_handle: driver.switch_to.window(h) ​ ​ # 窗口截图 driver.get_screenshot_as_file(filename=) # filename 为图片保存路径包含文件名

2.元素操作

# 获取元素 element = driver.find_element_by_id("kw") element = driver.find_element_by_name("wd") element = driver.find_element_by_class_name("s_ipt") elements = driver.find_elements_by_tag_name("input") xinwen = driver.find_element_by_link_text("新闻") # 精确查询 xinwen = driver.find_element_by_partial_link_text("新") # 模糊查询 element = driver.find_element_by_xpath("/html/body/div/div/div[5]/div/div/form/span/input") # div[5]为集合,从1开始, 绝对路径 element = driver.find_element_by_xpath("//input[@id='kw' and @class='s_ipt']") 相对路径 element = driver.find_element_by_css_selector("#kw") ​ ​ # 操作元素 element.send_keys("软件测试") # 输入 软件测试 element.click() # 点击 element.clear() # 清除文本 element.size 返回元素的大小 element.text 返回元素的文本 element.get_attribute("xxx") 获取属性值 element.is_displayed() 判断元素是否可见 element.is_enable() 判断元素是否可用 element.is_selected() 判断元素是否选中 ​ ​ # 元素等待:在定位页面元素时,如果未找到,会在指定时间内一直等待的过程。 from selenium.webdriver.support.wait import WebDriverWait # 隐式等待 driver.implicitly_wait(30) # 隐式等待为全局设置,作用于所有元素 # 显式等待 wait = WebDriverWait(driver=driver, timeout=30, poll_frequency=0.5) element = wait.until(lambda x: x.find_element_by_id('kw')) ​ ​ # 操作cookie driver.get_cookie(name=) # 获取指定 cookie driver.get_cookies() # 获取本网站所有本地 cookie driver.add_cookie(cookie_dict=) # 添加 cookie cookie_dict 一个字典对象,必须的包括 name 和 value

3.鼠标操作

from selenium.webdriver import ActionChains ​ # 实例化对象 action = ActionChains(driver) # 方法 action.click(element) 点击 action.context_click(element) 右击 action.double_click(element) 双击 action.drag_and_drop(source=, target=) 拖动 action.drag_and_drop_by_offset(source=, xoffset=, yoffset=) 拖动 action.move_to_element(element) 悬停 action.move_by_offset(xoffset=,yoffset=) 悬停 action.perform() 执行,此方法用来执行以上所有鼠标操作 # 注意 右键菜单无法点击,不能取消,要使用键盘按钮一同使用。 ​ button = driver.find_element_by_css_selector("input[type='submit']") action.move_to_element(button).perform() action.click().perform()

4.键盘操作

from selenium.webdriver.common.keys import Keys ​ element.send_keys(Keys.BACK_SPACE) 删除backspace element.send_keys(Keys.SPACE) 空格 element.send_keys(Keys.TAB) 制表键tab element.send_keys(Keys.ESCAPE) 回退键esc element.send_keys(Keys.ENTER) 回车enter element.send_keys(Keys.CONTROL, 'a') 全选ctrl+a element.send_keys(Keys.CONTROL, 'c') 复制ctrl+c

5.文件操作

# 上传文件按钮 element = driver.find_element_by_css_selector("[name='upload']") # 上传文件 element.send_keys("D:\hello.txt")

6.表单操作

from selenium.webdriver.support.select import Select ​ # 获取select对象, el为select标签 Select(el).select_by_index() # 通过下标 Select(el).select_by_value() # 通过value Select(el).select_by_visible_text() # 通过文本

7.弹出框操作

# 获取弹出框对象, 弹出框类型 alert confirm prompt alert = driver.switch_to.alert # 调用方法 alert.text # 返回文字信息 alert.accept() # 接收对话框选项 alert.dismiss() # 取消对话框选项

4.数据传入方式

1.JSON

import json ​ # 字典 - 》 json json.dumps(data) print("字典 - 》 json ") data = {"name":"张三", "age":18} print(" 转换前的数据类型:", type(data)) print(" dict :", data) string = json.dumps(data) print(" 转换后的数据类型:", type(string)) print(" json : ", string) ​ # json - 》 字典 json.loads(data2) print("字典 - 》 json") data2 = '{"name":"张三", "age":18}' # 属性名必须使用双引号 print(" 转换前的数据类型:", type(data2)) print(" json :", data2) string2 = json.loads(data2) print(" 转换后的数据类型:", type(string2)) print(" dict : ", string2) ​ ​ ​ # 写入文件 data = {"name":"李四", "age":20} with open("./write.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False) ​ # 文件读取 with open("./data.json", encoding="utf-8") as f: data = json.load(f) print(data)

5.UnitTest框架

''' UnitTest 框架是 Python 自带的一个单元测试框架,用来做单元测试。 1. TestCase 测试用例 2. TestSuite 测试套件 3. TextTestRunner 以文本形式运行测试用例,用来执行测试用例和测试套件 4. TestLoader 批量执行测试用例 5. Fixture 固定装置,两个固定的函数,一个初始化,一个结束。 '''

1.TestCase

import unittest ​ ''' TestCase 1. 导包 import unittest 2. 测试类 继承 unittest.TestCase 3. 测试方法 以test开头 若无法运行,则 File -> Settings -> Tools -> Python Integrated Tools -> default test runner 选择需要的框架 '''

2.TestSuite

import unittest ​ ''' TestSuite 测试套件,多条测试用例集合再一起 1. 实例化 suite = unittest.TestSuite() 2. 添加用例 suite.addTest(test=) 3. 添加扩展 suite.addTest(unittest.makeSuite(testCaseClass=)) 将类testCaseClass中以test开头的方法添加到测试套件中 '''

3.TextTestRunner

import unittest ​ ''' TextTestRunner 用来执行测试用例和测试套件 1. 实例化:runner = unittest.TextTestRunner() 2. 执行: runner.run(test=) test 为测试用例或测试套件 ​ '''

4.TestLoader

''' TestLoader 用来加载 TestCase 到 TestSuite 中 # start_dir 为测试用例的目录 # pattern 匹配文件的格式 如:test*.py 匹配以test开头的py文件 # top_level_dir 默认为 None,可不传 suite = unittest.TestLoader.discover(start_dir=, pattern=, top_level_dir=) ​ 区别: TestSuite 需要手动添加测试用例,可以添加测试类,也可以添加测试类中的测试方法。 TestLoader 搜索指定目录下指定开头.py文件,添加测试类中所有测试方法,不能指定测试方法。 '''

5.Fixture

import unittest ​ ''' Fixture 装置 ,对一个测试用例环境的初始化和销毁就是一个 Fixture 1.初始化函数: def setUp() # 每个测试方法前都运行 2.结束函数: def tearDown() # 每个测试方法后都运行 Fixture 级别: 1.函数级别 setUp tearDown 2.类级别 setUpClass tearDownClass 3.模块级别 setUpModule tearDownModule ''' def setUpModule(): print("setUpModel------") ​ def tearDownModule(): print("tearDownModel------") ​ class Test05(unittest.TestCase): @classmethod def setUpClass(cls) -> None: print("setUpClass执行") @classmethod def tearDownClass(cls) -> None: print("tearDownClass执行") ​ def setUp(self): print("setUp执行") def tearDown(self) -> None: print("tearDown执行") ​ def test01(self): print("test01执行") ​ def test02(self): print("test02执行")

6.断言 assert

self.assertTrue(expr=,msg=None) # 验证expr是否为true self.assertFalse(expr=,msg=None) # 验证 expr 是否为 false self.assertEqual(first=,second=,msg=None) # 验证 first == second self.assertNotEqual(first=,second=,msg=None) self.assertIsNone(obj=, msg=None) self.assertIsNotNone(obj=,msg=None) self.assertIn(member=, container=,msg=None) # 验证container中是否包含member self.assertNotIn(member=,container=,msg=None)

7.添加测试数据

import unittest from parameterized import parameterized ​ ''' parameterized 的应用 1.导包 from parameterized import parameterized 2.修饰测试函数 @parameterized.expand(列表类型数据) 3.在测试函数中使用变量接收值 语法: 1.单个参数:值为列表 2.多个参数:值为列表嵌套元组 如:[(1,2,3),(2,3,4)] ''' def get_data(): return [(1, 2, 3), (2, 3, 4), (3, 4, 5)] ​ # 定义测试类 class Test07(unittest.TestCase): # 单个参数 @parameterized.expand(['1','2','3']) def test01(self, num): print(num) ​ # 多个参数 @parameterized.expand([(1,2,3),(2,3,4),(3,4,5)]) def test03(self, num1, num2, result): print("{}+{}={}".format(num1,num2,result)) ​ ​ @parameterized.expand(get_data()) def test04(self, a, b, c): print(a, "+", b, "=", c)

8.跳过测试

@unittest.skip('代码未完成') # 直接将测试函数标记成跳过 @unittest.skipIf(condition=, reason=) # 根据条件判断测试函数是否跳过

9.生成测试报告

import time import unittest from jd_HTMLTestRunner import HTMLTestRunner ​ ''' 基于 unittest 框架执行生成 html 报告 ''' suite = unittest.defaultTestLoader.discover("./", "d01*.py") report_dir = "../report/{}.html".format(time.strftime("%Y %H_%M_%S")) with open(report_dir, "wb") as f: HTMLTestRunner(stream=f, verbosity=2, title="xx项目自动化测试报告", description="操作系统win10").run(suite)

6.日志处理

1.简单使用

import logging ​ ''' 日志级别: debug -> info -> warning -> error -> critical ''' # 日志格式 formatter = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d] - %(message)s" ​ # 日志保存到指定文件 filename = "./log/log01.log" ​ # 设置日志级别 默认级级别 WARNING #logging.basicConfig(level=logging.DEBUG) # 输出在控制台 #logging.basicConfig(level=logging.INFO, format=formatter) # 输出在控制台,使用格式 logging.basicConfig(level=logging.INFO, format=formatter, filename=filename) # 输出到文件 ​ # 只会显示 大于等于 日志级别的日志信息 logging.debug("this is a debug") logging.info("this is a info") logging.warning("this is a warning") logging.error("this is a error") logging.critical("this is a critical")

2.四大组件

''' 日志模块四大组件 1.日志器 Logger:提供了程序使用日志的入口 2.处理器 Handler:将日志记录发送到合适的目的输出 3.格式器 Formatter:决定日志记录的最终输出格式 4.过滤器 Filter:提供了更细粒度的控制工具来决定输出那条日志记录,丢弃那条日志记录 ​ Logger 用法 logger.debug() logger.info() logger.warning() logger.error() logger.critical() logger.setLevel() 设置日志级别 logger.addHandler() 添加一个 handler 对象 logger.addFilter() 添加一个 filter 对象 ​ Handler 对象 : 将消息分发到 handler 指定的位置,比如 控制台、文件、网络、邮箱等。 Handler 是一个接口,需要实例化具体的子类 logging.StreamHandler 将日志输出到 Stream , 如 std.out \ std.err logging.FileHandler 将日志发送到磁盘文件,默认文件大小无限增长 logging.handlers.RotatingFileHandler 将日志发送到磁盘文件,支持日志文件按大小切割 logging.handlers.TimedRotatingFileHandler 将日志发送到磁盘文件,支持日志文件按时间切割 ​ Formatter 对象 用于配置日志信息的格式 logging.Formatter(fmt=, datefmt=, style=) # fmt 指定消息格式化字符串 # datefmt 指定日期格式字符串 # style 默认为 % ''' ​ # 导入包名,可以使用其下的 init 文件 import logging # 导入模块 import logging.handlers ​ # 使用 Logger logger = logging.getLogger(name="myLogger") logger.setLevel(logging.INFO) ​ # 添加 Handler sh = logging.StreamHandler() logger.addHandler(sh) # when: S 按秒分 M 按分钟分, H 按小时分, D 按天分 # interval: 间隔 # backupCount:保留文件数量 th = logging.handlers.TimedRotatingFileHandler(filename="./log/logtime.log", when="M", interval=1, backupCount=3, encoding="utf-8") logger.addHandler(th) ​ # 添加 Formatter formatter = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d] - %(message)s" fmt = logging.Formatter(formatter) sh.setFormatter(fmt) th.setFormatter(fmt) ​ logger.info("log -- info") # 文件 和 控制台 都能输出

3.封装日志,单例模式

''' 封装日志 ''' ​ import logging.handlers ​ # 单例模式 class GetLogger: logger = None ​ # 单例模式 @classmethod def get_logger(cls, filename="./log/logtime.log", when="M", interval=1, backupCount=3, encoding="utf-8"): if cls.logger is None: # 使用 Logger cls.logger = logging.getLogger() cls.logger.setLevel(logging.INFO) ​ # 添加 Handler sh = logging.StreamHandler() cls.logger.addHandler(sh) # when: S 按秒分 M 按分钟分, H 按小时分, D 按天分 # interval: 间隔 # backupCount:保留文件数量 th = logging.handlers.TimedRotatingFileHandler(filename, when, interval, backupCount, encoding) cls.logger.addHandler(th) ​ # 添加 Formatter formatter = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d] - %(message)s" fmt = logging.Formatter(formatter) sh.setFormatter(fmt) th.setFormatter(fmt) return cls.logger ​ if __name__ == '__main__': logger1 = GetLogger().get_logger() logger2 = GetLogger().get_logger() print("两个logger是否相等:{}".format(logger1 == logger2)) logger1.info("123456")

7.PO模式

Page Object(页面对象)

核心思想是通过对界面元素的封装减少冗余代码,主要体现在对界面交互细节的封装,也就是在实际测试中只关注业务流程;同时在后期维护中,若元素定位发生变化, 只需要调整页面元素封装的代码,提高测试用例的可维护性、可读性。

1.对象库层

Base(基类) :封装page 页面一些公共的方法,如初始化方法、查找元素方法、点击元素方法、输入方法、获取文本方法、截图方法等

''' page 页面一些公共方法 ''' from selenium.webdriver.support.wait import WebDriverWait ​ ​ class Base: def __init__(self, driver): self.driver = driver ​ # loc 为元组, 如 (By.CSS_SELECTOR, ".tel") # 使用*loc解包 def base_find_element(self, loc, timeout=30, poll=0.5): return WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll).until(lambda x:x.find_element(*loc)) ​ def base_click(self, loc): self.base_find_element(loc).click() ​ def base_input(self, loc, value): el = self.base_find_element(loc) el.clear() el.send_keys(value) ​ def base_get_text(self, loc): return self.base_find_element(loc).text ​ def base_get_image(self): self.driver.get_screenshot_as_file("../../../img/v4-fail.png")

2.操作层

page(页面对象):封装对元素的操作,一个页面封装成一个对象

# __init__.py from selenium.webdriver.common.by import By ​ login_username = By.ID, "u" login_pwd = By.ID, "pwd" login_code = By.ID, "code" login_btn = By.ID, "login" text = By.ID, "msg"
# page_login.py from PO模式.v4.base.base import Base from PO模式.v4 import page ​ class PageLogin(Base): # 输入用户名 def page_input_username(self, username): self.base_input(page.login_username, username) # 输入密码 def page_input_password(self, pwd): self.base_input(page.login_pwd, pwd) # 输入验证码 def page_input_code(self, code): self.base_input(page.login_code, code) # 登录 def page_click_login_btn(self): self.base_click(page.login_btn) # 获取信息 def page_get_text(self): return self.base_get_text(page.text) # 截图 def page_get_img(self): self.base_get_image() ​ # 组装业务 def page_login(self, username, pwd, code): self.page_input_username(username) self.page_input_password(pwd) self.page_input_code(code) self.page_click_login_btn() self.page_get_text() self.page_get_img()

3.业务层

import unittest from PO模式.v4.page.page_login import PageLogin from selenium import webdriver from parameterized import parameterized ​ ​ def get_data(): return [ ("15122223333", "123456", "8888", "账号不存在!"), ("15100001111", "123123", "8888", "密码错误!") ] ​ class TestLogin(unittest.TestCase): login = None ​ @classmethod def setUpClass(cls) -> None: driver = webdriver.Chrome() # 打开谷歌 driver.maximize_window() # 窗口最大化 # driver.implicitly_wait(30) # 隐式等待 url = 'D:\Codes\PyCharmProject\webdriver自动化测试\html\login.html' driver.get(url) # 打开 url cls.login = PageLogin(driver) ​ @classmethod def tearDownClass(cls) -> None: cls.login.driver.quit() ​ # 登录测试代码 @parameterized.expand(get_data()) def test_login(self, username, pwd, code, expect): self.login.page_login(username, pwd, code) msg = self.login.page_get_text() try: self.assertEqual(msg, expect) except AssertionError: self.login.page_get_img()

感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询