2026/6/1 4:18:05
网站建设
项目流程
网站建设流程包括哪些内容,如何做好一个企业网站,平面设计班,外贸定制网站建设电话web自动化测试工具-Selenium
Selenium 是一个开源的 web 自动化测试工具#xff0c;免费#xff0c;主要做功能测试。
1.特点 开源 跨平台#xff1a;linux、windows、mac 支持多种浏览器 支持多种语言 成熟稳定 功能强大
2.环境搭建
2.1.基于Python环境搭建 Pyth…web自动化测试工具-SeleniumSelenium 是一个开源的 web 自动化测试工具免费主要做功能测试。1.特点开源跨平台linux、windows、mac支持多种浏览器支持多种语言成熟稳定功能强大2.环境搭建2.1.基于Python环境搭建Python开发环境安装selenium包# 安装 pip intsall selenium pip intsall selenium2.48.0 # 查看 pip show selenium # 卸载 pip uninstall selenium安装浏览器安装浏览器驱动 – 保证能够用程序驱动浏览器实现自动化。# 安装地址 谷歌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看框架的nameid或者定位到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[idkw and classs_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(driverdriver, timeout30, poll_frequency0.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 和 value3.鼠标操作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[typesubmit]) 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) 全选ctrla element.send_keys(Keys.CONTROL, c) 复制ctrlc5.文件操作# 上传文件按钮 element driver.find_element_by_css_selector([nameupload]) # 上传文件 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.JSONimport 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, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse) # 文件读取 with open(./data.json, encodingutf-8) as f: data json.load(f) print(data)5.UnitTest框架 UnitTest 框架是 Python 自带的一个单元测试框架用来做单元测试。 1. TestCase 测试用例 2. TestSuite 测试套件 3. TextTestRunner 以文本形式运行测试用例用来执行测试用例和测试套件 4. TestLoader 批量执行测试用例 5. Fixture 固定装置两个固定的函数一个初始化一个结束。 1.TestCaseimport unittest TestCase 1. 导包 import unittest 2. 测试类 继承 unittest.TestCase 3. 测试方法 以test开头 若无法运行则 File - Settings - Tools - Python Integrated Tools - default test runner 选择需要的框架 2.TestSuiteimport unittest TestSuite 测试套件多条测试用例集合再一起 1. 实例化 suite unittest.TestSuite() 2. 添加用例 suite.addTest(test) 3. 添加扩展 suite.addTest(unittest.makeSuite(testCaseClass)) 将类testCaseClass中以test开头的方法添加到测试套件中 3.TextTestRunnerimport 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.Fixtureimport 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.断言 assertself.assertTrue(expr,msgNone) # 验证expr是否为true self.assertFalse(expr,msgNone) # 验证 expr 是否为 false self.assertEqual(first,second,msgNone) # 验证 first second self.assertNotEqual(first,second,msgNone) self.assertIsNone(obj, msgNone) self.assertIsNotNone(obj,msgNone) self.assertIn(member, container,msgNone) # 验证container中是否包含member self.assertNotIn(member,container,msgNone)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(streamf, verbosity2, titlexx项目自动化测试报告, 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(levellogging.DEBUG) # 输出在控制台 #logging.basicConfig(levellogging.INFO, formatformatter) # 输出在控制台使用格式 logging.basicConfig(levellogging.INFO, formatformatter, filenamefilename) # 输出到文件 # 只会显示 大于等于 日志级别的日志信息 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(namemyLogger) 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, whenM, interval1, backupCount3, encodingutf-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, whenM, interval1, backupCount3, encodingutf-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, timeout30, poll0.5): return WebDriverWait(self.driver, timeouttimeout, poll_frequencypoll).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()感谢每一个认真阅读我文章的人礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走这些资料对于【软件测试】的朋友来说应该是最全面最完整的备战仓库这个仓库也陪伴上万个测试工程师们走过最艰难的路程希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取