0


【PO框架总结】ui自动化selenium,清新脱俗代码,框架升级讲解

一:简化

1. 新建common 包 新建diver.py

封装浏览器驱动类

  1. from selenium import webdriver
  2. class Driver():
  3. """
  4. 浏览器驱动类
  5. 定义 一个【获取浏览器驱动对象driver的方法】。支持多种类型浏览器
  6. """
  7. def get_driver(self,browser_type):
  8. if browser_type == 'chrome':
  9. self.driver = webdriver.Chrome()
  10. elif browser_type == 'Firefox':
  11. self.driver = webdriver.Firefox()
  12. # 最大化窗口、隐式等待、最大加载时长
  13. self.driver.maximize_window()
  14. self.driver.implicitly_wait(20)
  15. self.driver.set_page_load_timeout(20) # 页面加载时长, 超时则停止,避免因页面加载过慢而拖延整个测试流程
  16. return self.driver

新建configs包,config.py

把超时时间,隐式等待时间写到配置里

两种写配置的方式,都行

  1. # 页面允许超时时间 小技巧 按 ctrl +shift +U, 可以转大写
  2. SET_PAGE_LOAD_TIMEOUT = 20
  3. # 默认浏览器类型
  4. DEF_BROWSER_TYPE = 'chrome'

我用第二种方式,那么在driver.py 中,就这么导入

  1. from configs.config import SET_PAGE_LOAD_TIMEOUT,DEF_BROWSER_TYPE

driver.py 中,引入config的配置的时间,引用config中配置的浏览器类型

  1. from selenium import webdriver
  2. from configs.config import SET_PAGE_LOAD_TIMEOUT,DEF_BROWSER_TYPE
  3. class Driver():
  4. """
  5. 浏览器驱动类
  6. 定义 一个【获取浏览器驱动对象driver的方法】。支持多种类型浏览器
  7. """
  8. def get_driver(self,browser_type = DEF_BROWSER_TYPE):
  9. if browser_type == 'chrome':
  10. self.driver = webdriver.Chrome()
  11. elif browser_type == 'Firefox':
  12. self.driver = webdriver.Firefox()
  13. # 最大化窗口、隐式等待、最大加载时长
  14. self.driver.maximize_window()
  15. self.driver.implicitly_wait(20)
  16. self.driver.set_page_load_timeout(SET_PAGE_LOAD_TIMEOUT) # 页面加载时长, 超时则停止,避免因页面加载过慢而拖延整个测试流程
  17. return self.driver

2. 新建页面基类

common包中,新建basePage.py , BasePage类

表示页面基类, 把不同的页面,能做的同样的事情,都封装在这个类中。

**new_Driver() **方法,返回的是driver,页面类示例对象就可以用到

back() ,表示二次封装的回退方法

get_element(), 表示定位方法

input_text ,表示文本框的输入方法

暂时先写这么多,还可以封装点击, 等等方法

  1. from common.driver import Driver
  2. class BasePage:
  3. """
  4. 页面基类:不同的页面 能做同样的事,封装在这个类中
  5. 打开浏览器、进入页面、定位元素、点击、输入等
  6. """
  7. def __init__(self):
  8. self.driver = Driver().get_driver() # 这个就表示打开浏览器
  9. # 打开网址
  10. def open_url(self,url): # 二次封装,提供更多的可能性
  11. self.driver.get(url)
  12. # 定位到元素
  13. def get_element(self,locator):
  14. """
  15. :param locator: 如: 'id','kw'
  16. :return:
  17. """
  18. return self.driver.find_element(*locator)
  19. # 输入文本
  20. def input_text(self,locator,text,append=False):
  21. # 默认:清空后输入
  22. if not append:
  23. self.get_element(locator).clear()
  24. self.get_element(locator).send_keys(text)
  25. # 否则是追加输入
  26. else:
  27. self.get_element(locator).send_keys(text)
  28. # 返回driver对象, 让页面对象灵活操作
  29. def new_Driver(self):
  30. return self.driver
  31. # 倒退
  32. def back(self):
  33. self.driver.back()

3.新建pages包

一个页面一个py文件, 在pages目录下,

新增baidu_page.py

表示 百度的页面,里面

有纯元素,比如下面的 “【百度一下】 按钮元素”

有元素做动作的方法,“输入框输入文本”

在main中,可以进行调试

  1. from common.basePage import BasePage
  2. # 继承基类
  3. class BaiduPage(BasePage):
  4. def open_baidu_page(self):
  5. # self.open_url(f"{URL}/login")
  6. self.open_url("https://www.baidu.com/")
  7. return self # 返回后,可以链式调用 BaiduPage().open_baidu_page().login_polly('花西子262','123456')
  8. # (动作)输入框输入xx
  9. def input_ele_input(self,text):
  10. self.input_text(('id','kw'),text)
  11. # (元素) 百度一下 按钮
  12. def submit_ele(self):
  13. return self.get_element(('id','su'))
  14. Baidu_Page_Obj = BaiduPage()
  15. if __name__ == '__main__':
  16. Baidu_Page_Obj = BaiduPage()
  17. # 输入
  18. Baidu_Page_Obj.open_baidu_page().input_ele_input("测试一下")
  19. # 点击确定
  20. Baidu_Page_Obj.submit_ele().click()

新建sahitest_page.py

再新增一个页面,其中,封装了两个元素

main 中

  1. 点击一个元素,然后 使用 basePage中封装的 back方法,回退
  2. 再点击另一个元素,使用basePage中,先获取到driver,然后再用driver
  1. import time
  2. from common.basePage import BasePage
  3. # 继承基类
  4. class SahiTestPage(BasePage):
  5. def open_sahi_page(self):
  6. self.open_url("https://sahitest.com/demo/")
  7. return self
  8. # (元素1)
  9. def _ele1(self):
  10. return self.get_element(("link text",'Drag Drop Test'))
  11. # (元素2)
  12. def _ele2(self):
  13. return self.get_element(("link text",'Alert Test'))
  14. sihi_Page_Obj = SahiTestPage()
  15. if __name__ == '__main__':
  16. sihi_Page_Obj = SahiTestPage()
  17. # 打开网址
  18. sihi_Page_Obj= sihi_Page_Obj.open_sahi_page()
  19. # 点击一个元素
  20. sihi_Page_Obj._ele2().click()
  21. time.sleep(2)
  22. # 回退 (使用封装的back方法)
  23. sihi_Page_Obj.back()
  24. # 点击第二个元素
  25. sihi_Page_Obj._ele1().click()
  26. time.sleep(2)
  27. # 回退(使用dirver对象 的)
  28. sihi_Page_Obj.new_Driver().back()

4 . 新建testCases包。

新建test_demo1.py

一个py文件就用来写一个 页面的测试用例,可以这么设计,那这个就写百度页面的测试用例。

我就直接两个用例,对应两个页面了

  • 用例1: 百度页面 输入 CSDN,百度一下
  • 用例2: sahitest页面,点击一个, 回退,点击另一个,再回退
  1. from pages.baidu_page import Baidu_Page_Obj
  2. from pages.sahitest_page import sihi_Page_Obj
  3. import time,pytest
  4. class Test_Demo():
  5. def test_case1(self):
  6. """打开百度"""
  7. Baidu_Page_Obj.open_baidu_page().input_ele_input("CSDN")
  8. Baidu_Page_Obj.submit_ele().click()
  9. time.sleep(1)
  10. def test_case2(self):
  11. """打开sihitest网页"""
  12. time.sleep(1)
  13. sihi_Page_Obj.open_sahi_page()
  14. # 点击一个元素
  15. sihi_Page_Obj._ele2().click()
  16. time.sleep(2)
  17. # 回退 (使用封装的back方法)
  18. sihi_Page_Obj.back()
  19. # 点击第二个元素
  20. sihi_Page_Obj._ele1().click()
  21. time.sleep(2)
  22. # 回退(使用dirver对象 的)
  23. sihi_Page_Obj.new_Driver().back()
  24. if __name__ == '__main__':
  25. pytest.main([__file__])

pytest的知识,要执行main中的代码要设置pycharm:不明白可以看 【自动化总结1】pytest使用整理

执行时,会完成测试用例 ,但是会打开两个浏览器。这个是可以去解决的问题

二:升级

集中管理元素定位、解决打开多个浏览器问题(如果只打开一次,就只登录一次就够了) 、

升级1:补充basePage,基类中的方法

get_element 查找元素,用显示等待

driver.py中,代码补充。get_element 查找元素,用显示等待的方式来查

  1. # 定位到元素
  2. def get_element(self,locator):
  3. """
  4. :param locator: 如: 'id','kw'
  5. :return:
  6. """
  7. # return self.driver.find_element(*locator)
  8. # 改用下面的显示等待的定位
  9. return WebDriverWait(driver=self.driver, timeout=10, poll_frequency=0.5).until(
  10. EC.visibility_of_element_located(locator))

和 get_elements 获取元素列表

  1. def get_elements(self, locator):
  2. # ------------这段代码生效否,有待考究----------------------
  3. WebDriverWait(
  4. # 传入浏览器对象
  5. driver=self.driver,
  6. # 传入超时时间
  7. #timeout=TIMEOUT, # 可以写到配置里
  8. timeout=10,
  9. # 传入轮询时间
  10. # poll_frequency=POLL_FREQUENCY).until( # 也可以写到配置里
  11. poll_frequency=0.5).until(
  12. EC.visibility_of_element_located(locator))
  13. # ------------这段代码生效否,有待考究----------------------
  14. # 返回元素列表
  15. return self.driver.find_elements(*locator)

再添加一个点击元素的方法。和获取元素文本的方法

  1. # 点击元素
  2. def click_element(self,locator):
  3. self.get_element(locator).click()
  4. # 获取元素文本信息(用来断言)
  5. def get_element_text(self, locator):
  6. # 获取元素文本(查找元素时,已经做了等待)
  7. return self.get_element(locator).text
  8. def get_elements_text(self,locator):
  9. #遍历得到每个元素的text
  10. return [ele.text for ele in self.get_elements(locator)]

写判断元素是否存在方法

  1. def isexist_element(self,locator,Action=""):
  2. '''
  3. 判断元素是否存在,注意要加异常捕获,不然还是超时
  4. :param locator:
  5. :param Action:
  6. :return:
  7. '''
  8. try:
  9. element = WebDriverWait(self.driver,
  10. timeout=10,
  11. poll_frequency=0.5) \
  12. .until(EC.element_to_be_clickable(locator))
  13. return element
  14. except:
  15. self.driver.save_screenshot(screenshots_path+f'\{Action}无法定位.png')
  16. # logru方式-----------------------------------------日志打不开
  17. # from utils.handle_loguru import logru
  18. # logru.error(f'{Action}元素无法定位')
  19. # 封装的logging方式------------------------------------
  20. from utils.handle_log import log
  21. log.info(f'{locator}{Action}元素无法定位')
  22. return False
  23. def isexist_element2(self,locator): # --这个和get_elements是一样的
  24. return self.driver.find_elements(*locator)

升级2:封装使用 元素定位器的yml文件or py文件

pages中写 login_page.py ,定位器写死

来写一次登录页,首先先把元素定位器写死

  1. from selenium.webdriver.common.by import By
  2. from common.basePage import BasePage
  3. from configs.config import HOST
  4. class LoginPage(BasePage):
  5. # 打开登录页面
  6. def open_loginpage(self):
  7. self.open_url(f"{HOST}/#/login")
  8. # def login_polly(self, username, password):
  9. # # 定位器是通过基类定义的方法获取的
  10. # # self.input_text([By.ID, 'username'], username)
  11. # time.sleep(0.5)
  12. # self.input_text(self.username_input, username)
  13. # time.sleep(0.5)
  14. # self.input_text(self.password_input, password)
  15. # time.sleep(0.5)
  16. # self.click_element(self.login_button)
  17. def login_polly(self, username, password):
  18. # 定位器是通过基类定义的方法获取的
  19. self.input_text([By.ID, 'username'], username)
  20. self.input_text(['id', 'password'], password)
  21. self.click_element(["id", "btnLogin"])
  22. if __name__ == '__main__':
  23. lp = LoginPage()
  24. lp.open_loginpage()
  25. lp.login_polly("hello","world")

管理定位器方式1(推荐):

新建 allelements.py 文件中。

按如下的方式,就是所有的页面的元素都写在一个类中。 还有一种思路可以尝试,一个页面一个类,这样就和yml方式一样了,更加的易读。

然后 login_page.py 中, 去读取配置。

管理定位器方式2 :使用yml文件(太复杂,没必要)

方式: 目标是在页面基类中的init方法中,就直接能获取各自页面的定位器。

1.在configs中,新建 allelements.yml

其中: LoginPage就表示 登录页, MainPage表示首页。 后续在定义页面类时,就要写同样的类名

  1. LoginPage: # 登录页面 这个key要和 class页面类名一致
  2. username_input : ["id", username] # 用户输入框 会默认成字符串
  3. password_input: ["id", "password"] # 密码输入框
  4. login_button: ["id", "btnLogin"] # 登录按钮
  5. message_text: [ 'css selector','.el-message--error' ] #登录错误消息文本
  6. message_text_less: [ 'css selector','.el-form-item__error' ] #密码不能小于3位
  7. MainPage: #首页
  8. home_button: [ 'xpath','//*[text()="首页"]' ] #首页按钮
  9. logout_button: [ 'xpath',"//span[text()='退出']" ] #退出按钮
  10. personal_button: [ 'xpath','//img' ] #个人中心按钮
  11. menu_productmanage: [ 'xpath',"//span[text()='商品管理']" ]
  12. submenu_pm_productlist: [ 'xpath',"//span[text()='商品列表']" ]
  13. submenu_pm_addproduct: [ 'xpath',"//span[text()='添加商品']" ]
  14. submenu_pm_productkind: [ 'xpath',"//span[text()='商品分类']" ]
  15. submenu_pm_producttype: [ 'xpath',"//span[text()='商品类型']" ]
  16. submenu_pm_brandmanage: [ 'xpath',"//span[text()='品牌管理']" ]
  17. submenu_pm_productattr: [ 'xpath',"//span[text()='商品规格']" ]
  18. submenu_pm_productgift: [ 'xpath',"//span[text()='赠礼列表']" ]
  19. submenu_pm_productconsult: [ 'xpath',"//span[text()='商品评论']" ]
  20. menu_ordermanage: [ 'xpath',"//span[text()='订单管理']" ]
  21. menu_membermanage: [ 'xpath',"//span[text()='会员管理']" ]
  22. today_orders: [ 'css selector','.el-row > div:nth-child(1) .total-value' ] #今日下单数
  23. today_sales: [ 'css selector','.el-row > div:nth-child(2) .total-value' ] #今日销售总额
  24. today_product: [ 'css selector','.el-row > div:nth-child(3) .total-value' ] #今日商品数
  25. today_members: [ 'css selector','.el-row > div:nth-child(4) .total-value' ] #今日会员
2. 新建utils包,新建 handle_path.py

有了它,路径大概率不会出错。

  1. f'{config_path}/allelements.yml' 这样就表示定位器的路径
  1. import os
  2. """
  3. 需求: 代码在任意路径都可以获取到项目工程的绝对路径
  4. """
  5. """工程路径"""
  6. project_path = os.path.dirname( os.path.dirname(os.path.abspath(__file__)))
  7. """配置路径"""
  8. config_path = os.path.join(project_path,'configs')
  9. """测试数据路径"""
  10. # case_data_path = os.path.join(project_path,'datas')
  11. # logs_path = os.path.join(project_path,'outFiles\logs')
  12. # screenshots_path = os.path.join(project_path,'outFiles\screenshots')
  13. # reports_path = os.path.join(project_path,'outFiles\\reports')
  14. common_path = os.path.join(project_path,'common')
  15. testcase_path = os.path.join(project_path,'testCases')
  16. if __name__ == '__main__':
  17. print(common_path)
3. 在utils包中,新建 handle_yml.py

里面写一个获取yml文件的方法。 获取出来得到 字典的形式, 长下面这个样子

  1. 在basePage.py 中, 更新init方法。
  1. from utils.handle_path import config_path
  2. from utils.handle_yml import get_yaml_data
  3. class BasePage:
  4. """
  5. 页面基类:不同的页面 能做同样的事,封装在这个类中
  6. 打开浏览器、进入页面、定位元素、点击、输入等
  7. """
  8. def __init__(self):
  9. self.driver = Driver().get_driver() # 这个就表示打开浏览器
  10. """
  11. 1.读取yml配置文件中各个页面的定位器
  12. - 哪个页面类继承basepage,就能得到哪个页面的定位器
  13. - 通过 self.__class__.__name__ 获取当前类名
  14. """
  15. self.locators = get_yaml_data(f'{config_path}/allelements.yml')[self.__class__.__name__]
  16. # 设置 实例 element_name 属性 的值是locator ----有利于代码编写
  17. for element_name, locator in self.locators.items():
  18. setattr(self, element_name, locator)

解析:其中:self.locators 就是一个字典。 把 键和值获取出来。

  1. 再用 setattr 设置成属性对。, 把他们变成属性,就可以通过,对象.属性,就能获取

4.使用定位器

首先类名要LoginPage和 yml文件中的是一致的、这样也可以运行, 这么做的好处时,页面元素好管理,代码也好读。

解决这个黄的,可以这么搞

再basePage中,加

  1. def __getitem__(self,item):
  2. return self.locators[item]

5.yml的优势和弊端分析

这种方式,是把定位器强行绑定到类 身上。可以通过类对象来获取, 代码上好读一点。

但是每次需要实例化一个类对象,才能使用,

比如这里的例子,它是登录页,登录成功后进入了首页。 代码中就必须要实例化一个首页类,才能拿到首页的定位器。并且还需要保持 yml文件中的名称 和类名一致,有点麻烦

升级3:控制运行用例时,只打开一个浏览器

之前为什么打开两个浏览器

能看到代码,进行两次测试用例时,都进行了一次实例化,每次实例化一下,都会走一次 get_driver方法

1. 修改成单例模式(不推荐,暂时不好理解)

单例的大概意思,就是这样写后,表示这个类只有一个实例对象, 目的是想要只有一个 self.driver

写一个单例类,并且Driver继承它

  1. class Single:
  2. def __new__(cls, *args, **kwargs):
  3. if not hasattr(cls,'instance'):
  4. cls.instance = super().__new__(cls, *args, **kwargs)
  5. return cls.instance

还需要修改修改

2. 把get_driver设置为类方法(推荐)

这样也能保证只有一个 cls.driver

上图的绿色不对,应该是不加括号,加括号都可以,表示类或者实例都能调用这个方法

  1. from selenium import webdriver
  2. from configs.config import SET_PAGE_LOAD_TIMEOUT,DEF_BROWSER_TYPE
  3. class Driver():
  4. """
  5. 浏览器驱动类
  6. 定义 一个【获取浏览器驱动对象driver的方法】。支持多种类型浏览器
  7. """
  8. driver=None
  9. @classmethod
  10. def get_driver(cls,browser_type = DEF_BROWSER_TYPE):
  11. if cls.driver is None:
  12. if browser_type == 'chrome':
  13. cls.driver = webdriver.Chrome()
  14. elif browser_type == 'Firefox':
  15. cls.driver = webdriver.Firefox()
  16. # 最大化窗口、隐式等待、最大加载时长
  17. cls.driver.maximize_window()
  18. cls.driver.implicitly_wait(20)
  19. cls.driver.set_page_load_timeout(SET_PAGE_LOAD_TIMEOUT) # 页面加载时长, 超时则停止,避免因页面加载过慢而拖延整个测试流程
  20. return cls.driver
  21. if __name__ == '__main__':
  22. s1 = Driver().get_driver()
  23. s2 = Driver().get_driver()
  24. print(id(s1))
  25. print(id(s1) ==id(s2)) # 为True表示单例生效

测试场景1:用例中,进行断言

testcases包中,新建test_login_success.py , 从这个文件命名中,可以看出,登录成功的用例会写到这里,登录失败的会写到其他地方。

但我一般,不会反复进行登录,我只会写一个登录成功的用例,执行后,后续就不会执行它了

这里主要介绍下如何断言。新建 test_login.py

利用。basePage 中定义的获取文本信息来进行断言、 或者获取页面标题,来进行断言

如登录成功后,获取页面标题,判断标题是不是“首页”

  1. from pages.login_page import LoginPage
  2. import pytest
  3. class Test_Demo():
  4. def test_case1(self):
  5. loginobj =LoginPage()
  6. loginobj.open_loginpage()
  7. loginobj.login_polly("朝天宫002",123456)
  8. """
  9. 方式1: 获取标题来进行断言
  10. """
  11. # assert loginobj.new_Driver().title == "首页"
  12. print("-----------------------------",loginobj.new_Driver().title) # 标题打印出来是“保利商城”
  13. """
  14. 方式1: 获取标题来进行断言
  15. """
  16. print("++++++++++++++++++++++++++++",loginobj.get_element_text(['xpath','//*[text()="首页"]']))
  17. assert loginobj.get_element_text(['xpath','//*[text()="首页"]']) == "首页"
  18. if __name__ == '__main__':
  19. pytest.main([__file__,'-s'])

测试场景2,在用例中使用数据驱动

同一个动作要执行多次,要考虑用例清除,比如登录用例,每次登录后要退出到登录页

登录成功时,用退出的方式,没有登录成功时,不用退出

所以登录用例还是有点麻烦(下面看着玩就好),建议不写这种用例,这里只是举例说明可以进行数据驱动

用例恢复

登录用例登录失败的情况

成功和失败都写到参数化里边,同时用例也写到一起

测试场景3:第一个用例失败,如何继续跑后续的用例

参考【自动化总结1】pytest使用整理_cento执行pytest,执行时用unitest-CSDN博客

测试场景4.解决需要登录后操作的问题

**方式1,每个用例都登录 **:

进行添加商品用例,每次先登录一次,然后再首页,一步步点到

添加商品页面的 添加商品方法

添加商品用例

再进入到商品列表页,进行断言

方式2(推荐):

直接写在这里,打开浏览器时,就进行登录,

然后其他页面直接get url 到页面里面去

如下图片,可以看出,打开浏览器就登录了一次,后续,直接进入页面操作就好了

测试场景5: 有些地方需要加日志、

加截图和日志同理

configs包中,新建logru.ini

  1. [log]
  2. format = {time:YYYY-MM-DD HH:mm:ss},{module}(line:{line}),{level}||{message}
  3. level = ERROR
  4. rotation = 10 MB
  5. retention = 2 days

再utils包中,新建handler_log.py

  1. print()
  2. """
  3. 日志相关内容:
  4. 1- 日志的输出渠道:文件xxx.log 控制台输出
  5. 2- 日志级别: DEBUG-INFO-WARNING-ERROR-CRITICAL
  6. 3- 日志的内容:2021-10-20 13:50:52,766 - INFO - handle_log.py[49]:我是日志信息
  7. 年- 月 - 日 时:分:秒,毫秒 -级别 -哪个文件[哪行]:具体报错信息
  8. https://www.liujiangblog.com/course/python/71
  9. """
  10. from time import strftime
  11. import logging
  12. from utils.handle_path import logs_path
  13. #这部分不存在单例
  14. def logger(fileLog=True,name=__name__):
  15. """
  16. :param fileLog: bool值,如果为True则记录到文件中否则记录到控制台
  17. :param name: 默认是模块名
  18. :return: 返回一个日志对象
  19. """
  20. #0 定义一个日志文件的路径,在工程的logs目录下,AutoPolly开头-年月日时分.log
  21. logDir = f'{logs_path}/AutoPolly-{strftime("%Y%m%d%H%M")}.log'
  22. #1 创建一个日志收集器对象
  23. logObject = logging.getLogger(name)
  24. #2- 设置日志的级别
  25. logObject.setLevel(logging.INFO)
  26. #3- 日志内容格式
  27. fmt = "%(asctime)s - %(levelname)s - %(filename)s[%(lineno)d]:%(message)s"
  28. formater = logging.Formatter(fmt)
  29. if fileLog:#输出到文件
  30. #设置日志渠道--文件输出
  31. handle = logging.FileHandler(logDir,encoding='utf-8')
  32. #日志内容与渠道绑定
  33. handle.setFormatter(formater)
  34. #把日志对象与渠道绑定
  35. logObject.addHandler(handle)
  36. else: #输出到控制台
  37. #设置日志渠道--控制台输出
  38. handle2 = logging.StreamHandler()
  39. #日志内容与渠道绑定
  40. handle2.setFormatter(formater)
  41. #把日志对象与渠道绑定
  42. logObject.addHandler(handle2)
  43. return logObject
  44. log = logger()#文件输出日志
  45. if __name__ == '__main__':
  46. log = logger(fileLog=False)#控制台输出日志
  47. log.info('我是日志信息')

handle_path.py 里边同时要加上 ,还要新建好文件 outFiles\logs

  1. logs_path = os.path.join(project_path,'outFiles\logs')

BasePage.py中就可以加一些日志,运行后会生成在一个文件。

查找元素方法,也可以增加错误日志打印

  1. # 定位到元素
  2. def get_element(self,locator):
  3. """
  4. :param locator: 如: 'id','kw'
  5. :return:
  6. """
  7. try:
  8. # return self.driver.find_element(*locator)
  9. log.info(f"定位了{locator}")
  10. # 改用下面的显示等待的定位
  11. return WebDriverWait(driver=self.driver, timeout=10, poll_frequency=0.5).until(
  12. EC.visibility_of_element_located(locator))
  13. except Exception as e:
  14. log.error(f"定位元素失败{e},元素{locator}找不到")

测试场景6,加alluer报告

参考 【自动化总结1】pytest使用整理_cento执行pytest,执行时用unitest-CSDN博客

标签: ui 自动化 selenium

本文转载自: https://blog.csdn.net/Ataoker/article/details/139768190
版权归原作者 A~taoker 所有, 如有侵权,请联系我们删除。

“【PO框架总结】ui自动化selenium,清新脱俗代码,框架升级讲解”的评论:

还没有评论