问题
问题贴:实例化driver的代码放到基类BasePage中的__init__初始化方法了,但是当__init__方法调用conftest.py文件中的全局变量web_env(用于存放经过多浏览器运行命令后的浏览器的类型名称),不等web_env经过pytest_configure方法就被调用了
想要实现的效果:
能让web_env这个变量能正常被__init__方法调用
报错信息
环境
python 3
问题贴:实例化driver的代码放到基类BasePage中的__init__初始化方法了,但是当__init__方法调用conftest.py文件中的全局变量web_env(用于存放经过多浏览器运行命令后的浏览器的类型名称),不等web_env经过pytest_configure方法就被调用了
想要实现的效果:
能让web_env这个变量能正常被__init__方法调用
python 3
你上代码看看,我怀疑你是没完全放到init里,或者你提前在某个地方提前init了。
代码结构:
conftest.py:
# 创建conftest.py 文件 ,将下面内容添加进去,运行脚本
# 在conftest.py配置里写方法可以实现数据共享,不需要import导入,可以跨文件共享
from _pytest.config import Config
from _pytest.config.argparsing import Parser
# 重写hook函数,修改默认编码unicode格式的测试用例,改为支持中文格式的unicode-escape
def pytest_collection_modifyitems(items):
"""
测试用例收集完成时,将收集到的用例名name和用例标识nodeid的中文信息显示在控制台上
"""
for i in items:
i.name = i.name.encode("utf-8").decode("unicode_escape")
i._nodeid = i.nodeid.encode("utf-8").decode("unicode_escape")
# 定义全局变量,用于存储浏览器的类型名称
web_env = {}
# 实现命令行注册,解决自定义参数(设置多浏览器运行命令行参数)报错问题
def pytest_addoption(parser: Parser):
"""
hook函数
1、通过 parser.getgroup创建/获取组名: hogwarts
2、addoption添加一个命令行选项:pytest xxx.py --browser=chrome
:param parser:
:return:
"""
hogwarts = parser.getgroup("hogwarts")
# pytest .\test_demo.py --browser=chrome
# pytest .\test_demo.py --driver=chrome
# 注册一个命令行参数
hogwarts.addoption("--browser", default="chrome", help="指定执行的浏览器")
# 第一个参数"--browser"为指定的命令行参数的形式:--browser=chrome、--driver=chrome
# 第二个参数 default="firefox" 指定参数的默认值
# 第三个参数 dest = "browser" 用于改写 第一个参数 "--browser" 的名称
# 第四个参数 help="指定执行的浏览器" 用于给 hogwarts 组名 做解释
def pytest_configure(config: Config):
"""
hook函数: 用于获取到指定传参参数的值(这个值为浏览器的名称,例如chrome)
:param config:
:return:
"""
config.addinivalue_line("markers",
"test_normal: mark test functions that test data type errors")
config.addinivalue_line("markers",
"test_data_type_error: mark test functions that test data type errors")
config.addinivalue_line("markers",
"test_data_range: mark test functions that test data type errors")
config.addinivalue_line("markers",
"test_zero_division_error: mark test functions that test data type errors")
browser = config.getoption("--browser")
browser_conf = {"browser": browser}
print(f"通过命令行获取到的浏览器名称为{browser_conf}")
web_env.update(browser_conf)
print(web_env)
base_page.py:
""" 基本类 """
import time
import os
from time import sleep
import allure
import yaml
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from conftest import web_env
# @auto_save_exception_screen_shot
class BasePage:
"""定义基地址"""
_BASE_URL = "https://work.weixin.qq.com/wework_admin/frame#index"
def __init__(self, base_driver=None):
"""
初始化
1、使用命令行参数、兼容多种类型的浏览器运行程序
2、实例化 self.driver,并复用浏览器
3、为每个页面设置 3 秒隐式等待
4、最大化浏览器窗口
5 、访问基地址 (访问企业微信登录页)
:param base_driver: 实例化类时,自带的实例化过的driver对象
"""
self.browser = web_env["browser"]
print(self.browser)
print(f"web_env的值为:{self.browser}")
if base_driver:
self.driver = base_driver
else:
print(web_env["browser"])
if self.browser == "chrome":
# 实例化Firefox浏览器的 self.driver,并复用浏览器
self.driver = webdriver.Chrome()
else:
# 实例化Firefox浏览器的 self.driver,并复用浏览器
self.driver = webdriver.Firefox()
self.reuse_browser()
self.driver.implicitly_wait(5)
self.driver.maximize_window()
if not self.driver.current_url.startswith("http"):
# 如果当前访问的浏览器url地址不是http网页,那么将导航到基地址中
self.driver.get(self._BASE_URL)
# 设置扫二维码登录的等待时间
sleep(10)
def reuse_browser(self):
"""
复用浏览器
1、实例化Options对象
2、修改 option 的 debugger_address 属性:"localhost:9222"
3、实例化 driver,需添加 Chrome 的 option 配置
:return:
"""
# 实例化Options对象
option = Options()
# 修改 option 的 debugger_address 属性:"localhost:9222", 这样可以使 localhost:9222 在 debug 模式下打开,便于调试
option.debugger_address = "localhost:9222"
# 实例化 driver,需添加 Chrome 的 option 配置
self.driver = webdriver.Chrome(options=option)
def get_cookies(self):
"""
复用cookie
1、登录成功后,获取 cookie 信息
2、将 cookie 存入本地文件
:return:
"""
# 登录成功后,获取 cookie 信息
cookies = self.driver.get_cookies() # 返回一个装了多个 cookie 的列表
# 将 cookie 存入本地文件
with open("../data/cookies.yaml", "w", encoding="utf8") as f:
# yaml.safe_dump , 将目标数据存放到指定文件
yaml.safe_dump(cookies, f)
def add_cookies(self):
"""
植入 cookie
1、从本地获取 cookies
2、为 self.driver 实例植入 cookie
3、退出
4、复用 cookie 登录
:return:
"""
# 获取本地 cookies
with open("../data/cookies.yaml", "r", encoding="utf8") as f:
cookies = yaml.safe_load(open("../data/cookies.yaml"))
# 植入 cookie
for cookie in cookies:
self.driver.add_cookie(cookie)
print(cookie)
def get_screen_shot(self):
"""
截图
1、设置截图保存路径,用带有时间戳的方式命名截图
2、截图, 并将截图保存到本地文件中
3、将截图导入到 allure 报告中
:return:
"""
time_tamp = time.time()
image_path = f"../test_case/image_path/image_{time_tamp}.png"
self.driver.save_screenshot(image_path)
allure.attach.file(image_path, name="picture", attachment_type=allure.attachment_type.PNG)
def get_page_source(self):
"""
获取page_source
1、设置page_source本地保存路径,用带有时间戳的方式命名page_source
2、访问到当前页面,并将 page_source 保存到本地文件中
3、截图
4、将 page_source 导入到 allure 报告中
:return:
"""
time_tamp = time.time()
page_source_path = f"../test_case/page_source/page_source_{time_tamp}.html"
ele = self.driver.current_url
self.driver.get(ele)
with open(page_source_path, "w", encoding="utf8") as f:
f.write(self.driver.page_source)
allure.attach.file(page_source_path, name="page_source", attachment_type=allure.attachment_type.HTML)
self.get_screen_shot()
def do_find(self, by, locator=None):
"""
定位界面某个元素节点
1、如果传入的是元素节点,则直接传参
2、如果传入的是带定位方式的元组,则先解包后传参
:param by:定位方式, 例:By.ID、By.NAME等
:param locator: 元素节点
:return: 返回定位到的元素节点对象
"""
if locator:
return self.driver.find_element(by, locator)
else:
return self.driver.find_element(*by)
def do_finds(self, by, locator=None):
"""
定位界面多个元素节点
1、如果传入的是元素节点,则直接传参
2、如果传入的是带定位方式的元组,则先解包后传参
:param by:定位方式, 例:By.ID、By.NAME等
:param locator: 元素节点
:return: 返回定位到的元素节点对象列表
"""
if locator:
return self.driver.find_elements(by, locator)
else:
return self.driver.find_elements(*by)
def do_send_keys(self, value, by, locator=None):
"""
输入框中输入信息
1、定位到输入框的位置
2、调用sendkeys()方法,输入信息
:return:
"""
ele = self.do_find(by, locator)
ele.clear()
ele.send_keys(value)
def webdriver_wait_until_element_find(self, locator: tuple):
"""
封装显示等待的等待条件:直到元素被找到,才能进行下一步操作
:param locator: (定位方式,元素节点)
:return: 返回等待条件结果为真
"""
return WebDriverWait(self.driver, 10).until(expected_conditions.visibility_of_element_located(locator))
def do_quit(self):
"""
退出浏览器,销毁浏览器进程
:return:
"""
self.driver.quit()
你的报错信息贴的不全,你把完整的报错堆栈发出来。我看了你的代码web_env一开始就初始化了。
10.0.26100.2161]
(c) Microsoft Corporation。保留所有权利。
D:\开发项目\selenium_test_WeCom>cd test_case
D:\开发项目\selenium_test_WeCom\test_case>pytest test_wecom.py --browser=chrome
通过命令行获取到的浏览器名称为{‘browser’: ‘chrome’}
{‘browser’: ‘chrome’}
======================================== test session starts =========================================
platform win32 – Python 3.12.0, pytest-8.3.3, pluggy-1.5.0 – D:\python3\python.exe
cachedir: .pytest_cache
rootdir: D:\开发项目\selenium_test_WeCom
configfile: pytest.ini
plugins: allure-pytest-2.13.5, ordering-0.6, xdist-3.6.1
collecting … [[‘Tony’, ‘test_01’, ‘12345678899’, ‘1585736247@qq.com’]]
collected 1 item
test_wecom.py::TestWeCom::test_add_member[Tony-test_01-12345678899-1585736247@qq.com] ERROR
=============================================== ERRORS ===============================================
______ ERROR at setup of TestWeCom.test_add_member[Tony-test_01-12345678899-1585736247@qq.com] _______
self = <class ‘selenium_test_WeCom.test_case.test_wecom.TestWeCom’>
def setup_class(self):
"""
复用 cookie 登录
1、登录成功后,获取 cookies 信息
2、将 cookies 存入本地文件
3、从本地获取 cookies
4、为 self.driver 实例植入 cookie
5、退出
6、复用 cookie 登录
:return:
"""
self.home = LoginPage().reuse_cookies_login()
test_wecom.py:30:
self = <page_obj.login_page.LoginPage object at 0x0000023D79441610>, base_driver = None
def __init__(self, base_driver=None):
"""
初始化
1、使用命令行参数、兼容多种类型的浏览器运行程序
2、实例化 self.driver,并复用浏览器
3、为每个页面设置 3 秒隐式等待
4、最大化浏览器窗口
5 、访问基地址 (访问企业微信登录页)
:param base_driver: 实例化类时,自带的实例化过的driver对象
"""
if base_driver:
self.driver = base_driver
else:
self.browser = web_env["browser"]
E KeyError: ‘browser’
…\page_obj\base_page.py:45: KeyError
====================================== short test summary info =======================================
ERROR test_wecom.py::TestWeCom::test_add_member[Tony-test_01-12345678899-1585736247@qq.com] - KeyError: ‘browser’
========================================== 1 error in 0.16s ==========================================
D:\开发项目\selenium_test_WeCom\test_case>pytest test_wecom.py --browser=chrome
通过命令行获取到的浏览器名称为{‘browser’: ‘chrome’}
{‘browser’: ‘chrome’}
======================================== test session starts =========================================
platform win32 – Python 3.12.0, pytest-8.3.3, pluggy-1.5.0 – D:\python3\python.exe
cachedir: .pytest_cache
rootdir: D:\开发项目\selenium_test_WeCom
configfile: pytest.ini
plugins: allure-pytest-2.13.5, ordering-0.6, xdist-3.6.1
collecting … [[‘Tony’, ‘test_01’, ‘12345678899’, ‘1585736247@qq.com’]]
collected 1 item
test_wecom.py::TestWeCom::test_add_member[Tony-test_01-12345678899-1585736247@qq.com] ERROR
=============================================== ERRORS ===============================================
______ ERROR at setup of TestWeCom.test_add_member[Tony-test_01-12345678899-1585736247@qq.com] _______
self = <class ‘selenium_test_WeCom.test_case.test_wecom.TestWeCom’>
def setup_class(self):
"""
复用 cookie 登录
1、登录成功后,获取 cookies 信息
2、将 cookies 存入本地文件
3、从本地获取 cookies
4、为 self.driver 实例植入 cookie
5、退出
6、复用 cookie 登录
:return:
"""
self.home = LoginPage().reuse_cookies_login()
test_wecom.py:30:
self = <page_obj.login_page.LoginPage object at 0x000002518D2C1610>, base_driver = None
def __init__(self, base_driver=None):
D:\开发项目\selenium_test_WeCom\test_case>pytest test_wecom.py --browser=chrome
通过命令行获取到的浏览器名称为{‘browser’: ‘chrome’}
{‘browser’: ‘chrome’}
======================================== test session starts =========================================
platform win32 – Python 3.12.0, pytest-8.3.3, pluggy-1.5.0 – D:\python3\python.exe
cachedir: .pytest_cache
rootdir: D:\开发项目\selenium_test_WeCom
configfile: pytest.ini
plugins: allure-pytest-2.13.5, ordering-0.6, xdist-3.6.1
collecting … [[‘Tony’, ‘test_01’, ‘12345678899’, ‘1585736247@qq.com’]]
collected 1 item
test_wecom.py::TestWeCom::test_add_member[Tony-test_01-12345678899-1585736247@qq.com] ERROR
=============================================== ERRORS ===============================================
______ ERROR at setup of TestWeCom.test_add_member[Tony-test_01-12345678899-1585736247@qq.com] _______
self = <class ‘selenium_test_WeCom.test_case.test_wecom.TestWeCom’>
def setup_class(self):
"""
复用 cookie 登录
1、登录成功后,获取 cookies 信息
2、将 cookies 存入本地文件
3、从本地获取 cookies
4、为 self.driver 实例植入 cookie
5、退出
6、复用 cookie 登录
:return:
"""
self.home = LoginPage().reuse_cookies_login()
test_wecom.py:30:
self = <page_obj.login_page.LoginPage object at 0x000002083D48F890>, base_driver = None
def __init__(self, base_driver=None):
"""
初始化
1、使用命令行参数、兼容多种类型的浏览器运行程序
2、实例化 self.driver,并复用浏览器
3、为每个页面设置 3 秒隐式等待
4、最大化浏览器窗口
5 、访问基地址 (访问企业微信登录页)
:param base_driver: 实例化类时,自带的实例化过的driver对象
"""
self.browser = None
if base_driver:
self.driver = base_driver
else:
========================================== 1 error in 0.20s ==========================================
D:\开发项目\selenium_test_WeCom\test_case>pytest test_wecom.py --browser=chrome
通过命令行获取到的浏览器名称为{‘browser’: ‘chrome’}
{‘browser’: ‘chrome’}
======================================== test session starts =========================================
platform win32 – Python 3.12.0, pytest-8.3.3, pluggy-1.5.0 – D:\python3\python.exe
cachedir: .pytest_cache
rootdir: D:\开发项目\selenium_test_WeCom
configfile: pytest.ini
plugins: allure-pytest-2.13.5, ordering-0.6, xdist-3.6.1
collecting … [[‘Tony’, ‘test_01’, ‘12345678899’, ‘1585736247@qq.com’]]
collected 1 item
test_wecom.py::TestWeCom::test_add_member[Tony-test_01-12345678899-1585736247@qq.com] ERROR
=============================================== ERRORS ===============================================
______ ERROR at setup of TestWeCom.test_add_member[Tony-test_01-12345678899-1585736247@qq.com] _______
self = <class ‘selenium_test_WeCom.test_case.test_wecom.TestWeCom’>
def setup_class(self):
"""
复用 cookie 登录
1、登录成功后,获取 cookies 信息
2、将 cookies 存入本地文件