如果是 unittest+python+pageobject+appium,如何让 driver 在各个 testcase 传递呢?
目前的想法是是使用可以在各个 py 文件间中传递的全局变量,但是总感觉不太好。basepage 是这样的:
class BasePage(object):
"""作为父类,包含driver成员变量,用于标识WebDriver,以便在子类中定位页面元素"""
# 初始化
def __init__(self, driver=None):
self.driver = driver
在一个新的文件中设置了一个全局变量:
def init():
global global_dict
global_dict = {}
def set_value(name, value):
global_dict[name] = value
def get_value(name):
try:
return global_dict[name]
except KeyError:
return None
在 testcase 中通过 get_value 取出来
在 start app 的 testcase 中 set_value 把 webdriver set 进去
就是初始化的时候,传入 driver 实栗
我是这么搞的
class Run:
driver = Run()
class BasePage:
def __init__(self, driver: WebDriver):
self.driver = driver
class TestDemo:
@classmethod
def setup_class(cls):
# run里面的driver
cls.driver = driver
全局使用 driver 不好吧,中间没有 driver 的获取跟释放么?
如果用 pytest 倒是很容易处理,可以很容易做全局变量,unittest 没尝试过
是用一个专门的类管理 driver 吗,如:
class driver:
def __init__(self, driver: None):
self.driver = driver
def run(self):
return self.driver
def quit(self):
self.driver.quit()
但是这样的话,每次初始化这个类都会初始化一次 driver
而且如果在 basePage 里面每次默认传入 webDriver,当我在一个 testcase 中初始化一个其他的 page 类,都会传入一个新的 webdriver,即重新打开 app 一次。
我们用的 pytest,在 conftest 里先初始化 driver
@pytest.fixture(scope='function')
def driver():
# setUp
get_driver = DriverConfig().driver_config()
yield get_driver
# tearDown
LoginPage().logout(get_driver)
get_driver.quit()
然后在测试用例里传入 driver
class TestAppEngineDF001:
@user2e
@pytest.mark.needUI
@allure.feature("AppEngine")
@allure.story("AppEngine.DF")
def test_df_001(self, driver):
# 用例名称
case_name = '/autotest/appengine/DF/001'
用例里再调用 page 类,driver 是传递下去的
with allure.step("2、点击添加按钮"):
ViewPage().view_click_operation_button(driver, '添加')
一直传到 selenium 的二次封装那部分.
def element_click(self, driver, locate_type, locator_expression, wait_for_locate_type=None,
wait_for_locator_expression=None, wait_for_disappear_locate_type=None,
wait_for_disappear_locator_expression=None, timeout=30):
"""
元素点击
:param driver: 浏览器驱动
:param locate_type: 定位方式类型
:param locator_expression: 定位表达式
:param wait_for_locate_type: 等待元素出现的元素定位方式类型
:param wait_for_locator_expression: 等待元素出现的元素定位表达式
:param wait_for_disappear_locate_type:等待元素消失的元素定位方式类型
:param wait_for_disappear_locator_expression:等待元素消失的元素定位表达式
:param timeout:超时时间
:return:
"""
# 元素要可见
element = self.element_visibility_appear(driver=driver, locate_type=locate_type,
locator_expression=locator_expression,
timeout=timeout)
try:
# 点击元素
element.click()
except(StaleElementReferenceException, ENI_Exception):
self.wait_for_ready_state_complete(driver=driver)
time.sleep(0.05)
element = self.element_visibility_appear(driver=driver, locate_type=locate_type,
locator_expression=locator_expression,
timeout=timeout)
element.click()
except Exception as e:
print("页面出现异常,元素不可点击", e)
return False
try:
# 点击元素后的元素出现或元素消失
self.element_visibility_appear(driver, wait_for_locate_type, wait_for_locator_expression)
self.element_visibility_disappear(driver, wait_for_disappear_locate_type,
wait_for_disappear_locator_expression)
except Exception as e:
print("等待元素消失或出现失败", e)
return False
return True
最方便的方法就是用一个 单例模式 初始化 driver 解决
run 类我用来启动程序,跳转每个 page ; 每个 case 都导入一次 run 里面的 driver;这样不会重新打开 app
class Run:
def __init__(self):
logger.info(f"开始启动应用")
self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
# 关闭程序
def close(self):
logger.info(f"执行关闭应用")
self.driver.quit()
driver = Run()
unittest 可以定义实例化只启动一次