300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > selenium UI自动化PO模式测试框架搭建

selenium UI自动化PO模式测试框架搭建

时间:2021-08-04 15:06:55

相关推荐

selenium UI自动化PO模式测试框架搭建

这里写目录标题

1、UI自动化规划2、PageObject设计模式系统梳理分类 3、PO模式封装1、驱动模块(`固定写法`)2、基类封装(`基本框架固定写法`)3、设置yaml定位元素(`固定写法`)4、读取yaml定位数据(`固定写法`)5、写PO页面-继承基类6、测试用例yaml7、pytest测试模块+allure测试报告输出8、PO模式结合fixture的数据清除与格式化 操作汇总

1、UI自动化规划

熟悉业务-》确定方案-》选取场景-》了解前端-》定位元素-》编写脚本-》运行优化-》回归报告-》项目汇总

价值意义:

自动化执行需要:模块化

需要可制定化执行

可复用性

PO模式:

将页面定位和业务分开,元素的定位单独处理,执行脚本单独封装。维护方便。

封装BasePage类,在基类中具有webdriver的实例的属性,把每个页面继承BasePage,通过driver管理每个页面的元素,将页面再细分一个个方法。Testcase依赖page类,进行组织化的测试步骤。

维护:

元素变化了:维护每个page

测试步骤变化:维护Testcase

每个page的常规操作封装基类:

点击动作、输入、文本处理、滑动、弹窗……

业务分类:

登录模块(登录、注册新用户)、

首页模块(菜单栏、主页显示)、

管理模块(数据列表展示、新增、分类、……)、

用户模糊(用户数据信息展示)……

功能测试用例依据以此分类设计

2、PageObject设计模式

系统梳理分类

代码层面分类:

系统System:

其中:

pageObjects

testCase

common

configs

utils

outFiles文件夹(logs/reports/screenshoot

docs文件夹

data文件夹

PO模式从下往上,从底层开始写:driver-》BasePage-》pages-》test执行-》报告

python+selenium+pytest+allure.

3、PO模式封装

1、驱动模块(固定写法

封装驱动写在:common包下

新建myDriver.py文件,建一个兼容浏览器的驱动类,就是dirver

"""驱动模块1、考虑到浏览器的兼容性,可以分为主流的几个浏览器驱动1、谷歌2、火狐3、其他"""from selenium import webdriverfrom configs.config import implicitly_wait_time# 设置单例模式'''类创建实例:1、先调用—__new__()创建方法,一般类中不写,自动调用2、再调用初始化方法__init__()判断一个类是否有实例,如果有,就不会创建新的实例 '''# 哪一个类的实例需要使用单例模式,就直接继承这个类(`固定写法`)class Single(object):#new方法创建对象def __new__(cls, *args, **kwargs):# 判断当前的类是否已经实例化if not hassttr(cls, '_instance'):cls._instance = super().__new__(cls)# super是父类的new方法return cls._instanceclass Driver(Single):# 新建一个初始值_driver = None# 判断使用浏览器,---------默认指定谷歌浏览器def get_driver(self, browser_name='chrome'):if self._driver is None:if browser_name == "chrome":self._driver = webdriver.Chrome()elif browser_name == "firefox":self._driver = webdriver.Firefox()else:raise (f"没有这个{browser_name}浏览器,请使用可用浏览器打开")# 设置隐式等等时间---设置`**全局变量`**等等时间5sself._driver.implicitly_wait(implicitly_wait_time)# 浏览器对大化self._driver.maximize_window()return self._driver # 返回浏览器对象if __name__ == '__main__':Driver().get_driver('chrome')# 创建实例对象,调用对应的方法,传什么浏览器使用什么浏览器

驱动模块封装完毕,后续只需要调用Driver().get_driver('chrome')就可以使用webdriver进行元素定位

等同于对driver= webdriver.Chrome()的封装,方便兼容不同浏览器。

1、隐式等待时间全局变量参数化

configs包下创建config文件,设置隐式等待时间参数5s或者10s,自定义

implicitly_wait_time = 5

2、基类封装(基本框架固定写法)

基类写在:common包下,新建一个文件basePage.py

创建基类basePage

作用:1、把基本的页面操作封装好,给其他页面继承使用

包含:2、点击操作(click)、输入框输入(input_text)、获取元素属性值(get_attrbute)、元素可见(visibility)、截图(save_screenshot)、清除(clear),获取文本内容(get_text)、显示等待presence_of(元素可见(visibility_of),可操作点击(clickable))……等操作指令的封装

from common.myDriver import Driverimport timeimport os.pathfrom utils.handle_logs import loggerfrom utils.handle_path import screenshot_path, config_pathfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.support.wait import WebDriverWaitfrom utils.handle_yaml import get_yaml_datafrom common.myDriver import Driverfrom configs_delivery.config import wait_timeout, wait_poll_frequencyclass BasePage:def __init__(self): # 调用basepage 需要的浏览器对象,默认谷歌浏览器self._driver = Driver().get_driver()# ------------------------封装截图方法---------------------------# 截图操作:可以使用浏览器对象去调用,也可以使用元素调用def get_page_screenshot(self, action=None):# 注意截图的描述:哪个动作+时间curTime = time.strftime('%Y%m%d%H%M%S', time.localtime())filepath = os.path.join(screenshot_path, f'{action}_{curTime}.png')# 截图操作self._driver.save_screenshot(filepath)# ----------------------封装页面操作------------------------# 1、封装-输入-操作def input_text(self, locator, text, action=None):''':param locator: 元素定位: locator定义为包含-元素定位方法-和-定位方式-的包 ----['id','name']:param text: 输入文本的内容:param action: 执行的动作描述,缺省参数'''# 1、元素定位# find_element(定位方式,定位表达式)element = self._driver.find_element(*locator) # "*"号解包# 2、很多输入框有默认提示文本,需要先清除element.clear()# 3、输入值element.send_keys(text)# 2、封装-点击-操作def click(self, locator, action=None):# 1、元素定位# find_element(定位方式,定位表达式)element = self._driver.find_element(*locator) # "*"号解包# 2、点击element.click()# 3、封装-清空-操作def clear(self, locator, action=None):# 1/元素定位element = self._driver.find_element(*locator)# 2/清空element.clear() # 4、封装 -获取文本内容-操作def get_text(self, locator, action=None):return WebDriverWait(self._driver,timeout=wait_timeout,poll_frequency=wait_poll_frequency).until(EC.visibility_of_element_located(locator)).text # ----封装显式等待---判断元素是否存在,如果没有获取到元素,使用显示等待判断----日志及截图-------def element_is_presence(self,locator,action=None,timeout=5,poll_frequency=0.5):''':param locator: 定位元素和定位方法和表达式,包('',''):param action: 动作描述,:param timeout: 等待时间设置:param poll_frequency: 等待频率'''# 1/设置显式等待时间try:WebDriverWait(self._driver,timeout=timeout,poll_frequency=poll_frequency).until(EC.presence_of_element_located(locator))except BaseException:# 1/打印log信息log.error(action)# 2/截图self.get_page_screenshot(action)# 3/元素不存在返回Falsereturn False# 如果存在返回Truereturn True

---------------------------------------------------

1、路径配置

上述:screenshot_path,在公共方法utils中封装,新建handle_path.py

需要的路径都可以提前封装好:(固定写法

import os# 1、工程路径# os.path.obspath(__file__) 当前文件路径# os.path.dirname()------获取上一层路径project_path = os.path.dirname(os.path.dirname(__file__))# 2、截图路径screenshot_path = os.path.join(project_path, r'outFiles\screenshot')# 3、日志路径logs_path = os.path.join(project_path, r'outFiles\logs')# 4、测试数据路径testcase_path = os.path.join(project_path, 'data')# 5、测试报告路径reports_path = os.path.join(project_path, r'outFiles\reports\tmp')# 6、配置路径config_path = os.path.join(project_path, 'configs')if __name__ == '__main__':# print(project_path)# print(screenshot_path)# print(logs_path)# print(reports_path)# print(testcase_path)print(config_path)

2、log的封装(固定方法)

utils包下新建handle_logs.py

基类中封装显示等待的时间需要截图、并抓取log

"""日志相关内容1、日志的输出渠道:文件xxx.logs 控制台输出2、日志级别:CRITICAL-ERROR-WARNING-INFO-DEBUG3、日志内容:-03-30 18:42:12, 234 INFO XXXXXXXX年月日.时分秒.级别-哪行代码出错-具体内容"""import loggingimport datetimefrom utils.handle_path import logs_pathdef logger(file_Log=True, name=__name__):logDir = f'{logs_path}-{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}.txt'# 1/创建日志收集器对象logObject = logging.getLogger()# 2/ 设置日志的级别logObject.setLevel(logging.DEBUG)# 3/ 日志内容格式fmt = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'formater = logging.Formatter(fmt)if file_Log: # log文件模式# 设置日志渠道 -文件输出handle = logging.FileHandler(logDir, encoding='utf-8')# 日志内容与渠道绑定handle.setFormatter(formater)# 把日志对象与渠道绑定logObject.addHandler(handle)else:# 设置日志渠道控制台 控制台输出handle2 = logging.StreamHandler()# 日志内容与渠道绑定handle2.setFormatter(formater)# 把日志对象与渠道绑定logObject.addHandler(handle2)return logObjectlog = logger() # 控台输出日志if __name__ == '__main__':log = logger() # 控制台输出日志log.debug('日志信息:')

3、

locator的定义:

selenium4 升级后定位方式变化为:driver.find_element(By.定位方法, '定位方式')格式

例如:ID定位某个元素:

login = driver.find_element(By.ID, 'btnLogin')

locator即是By.定位方法, '定位方式'这个包

4、封装页面操作:后续需要自行添加函数封装即可

显示等待如上封装,可见元素定位的封装方法如下

def element_is_presence(self,locator,action=None,timeout=5,poll_frequency=0.5):'''def element_is_visibility(self,locator,action=None,timeout=5,poll_frequency=0.5):# 1/设置显式等待可见元素定位时间try:ele = WebDriverWait(self._driver,timeout=timeout,poll_frequency=poll_frequency).until(#判断元素是否可见再执行定位EC.visibility_of_element_located(locator))except BaseException:# 1/打印log信息log.error(action)# 2/截图self.get_page_screenshot(f'{action}-元素定位不到')# 3/元素不存在直接抛出异常信息raise# 如果存在返回元素本身return ele

而封装的页面操作使用可见元素定位的方法修改为:

# 2、输入操作def click(self, locator, action=None):# 1、元素定位# element_is_visibility(定位方式,定位表达式)。元素是可见的再进行定位element = self.element_is_visibility(locator)# 2、点击element.click()

封装定位元素是可点击的方法

# ----------------------可见元素且是可点击的-----------------def element_is_clickable(self,locator,action=None,timeout=5,poll_frequency=0.5):# 1/设置显式等待可见元素定位时间try:ele = WebDriverWait(self._driver,timeout=timeout,poll_frequency=poll_frequency).until(# 判断元素是否可点击执行定位EC.element_to_be_clickable(locator))except BaseException:# 1/打印log信息log.error(action)# 2/截图self.get_page_screenshot(f'{action}-元素定位不到')# 3/元素不可点击直接抛出异常信息raise# 如果存在返回元素本身return ele

相应页面的操作封装方法:

# 2、输入操作def click(self, locator, action=None):# 1、元素定位# element_is_visibility(定位方式,定位表达式)。元素是可见的再进行定位element = self.element_is_clickable(locator)# 2、点击element.click()

5、wait_timeout, wait_poll_frequency在config中提前配置号

---------------------------------.----------------------------------------

3、设置yaml定位元素(固定写法

config包下新建一个文件locator.yaml写定位配置数据

【”定位方法“,”定位方式“】的写法即:.find_element_by_id('username '),取id和对应的属性值,八大元素定位法之一。若采用css或者xpath写法:message_text: [‘css selector’,‘.el-message--error’] #登录错误消息文本:css selector即定位方法,.el-message--error定位方式。构成了字典格式{xxx:{ss:['v','v'],ss:['v','v'],ss:['v','v']},{[],[]},{[],[]}},后续通过字典的键获取值执行操作

LoginPage:username_input: ['id','username']#登录账户pwd_input: ['id','pwd']#登录密码login_btn: ['id','btnLogin']#登录按钮message_text: ['css selector','.el-message--error'] #登录错误消息文本OtherPage:home_button: ['xpath','//*[text()="首页"]'] #首页按钮logout_button: ['xpath',"//span[text()='退出']"] #退出按钮personal_button: ['xpath','//img'] #个人中心按钮

4、读取yaml定位数据(固定写法

utils包下新建一个文件,handle_yanl.py处理获取yaml数据

import yamlfrom utils.handle_path import config_pathdef get_yaml_data(fileDir):#方法一# # 1、打开文件# fo = open(fileDir, 'r', encoding='utf-8')# # 2、读取文件# yaml_data = yaml.load(fo, Loader=yaml.FullLoader)# return yamldata#方法二with open(fileDir, encoding='utf-8') as fo:return yaml.safe_load(fo.read())if __name__ == '__main__':print(get_yaml_data(f'{config_path}\locator.yaml'))

5、写PO页面-继承基类

先写个基础常规的页面:后续还有优化的方法

在pageObject新建操作模块页面:比如:login_page.py,继承basePage

登录页面:

from utils.handle_path import config_pathfrom common.basePage import BasePagefrom configs.config import urlfrom time import sleepfrom utils.handle_yaml import get_yaml_dataclass LoginPage(BasePage): # 继承基类def to_login_page(self):self._driver.get(url) # 打开登录页面,url在config包中配置return self#登录网址返回self本身,方便后续调用# 1、登录def login(self, username, pwd):#读取yaml定位参数locator['LoginPage']提取键值数据locator = get_yaml_data(f'{config_path}\locator.yaml')['LoginPage']# 输入账号,locator['username_input']获取定位方法和定位方式,xxx填写容self.input_text(locator['username_input'], 'username', action='输入账号')# 输入密码self.input_text(locator['pwd_input'], 'pwd', action="输入密码")# 点击登录按钮self.click(locator['login_btn'], action="点击登录按钮")sleep(5)if __name__ == '__main__':# 登录页面LoginPage().to_login_page().login('uername','pwd' )

------------------------**注**---------------------------------

1、urlconfigs中配置后再调用

定位获取优化方法:

locator = get_yaml_data(f’{config_path}\locator.yaml’)[‘LoginPage’]

self.input_text(locator[‘username_input’], ‘username’, action=‘输入账号’)

一个项目上百个定位元素,每次都通过get_yaml_data文件处理数据,然后再通locator

一个获取定位方法和定位方式比较繁琐。

so:设计了巧妙的定位调用方法,脚本中对于定位不可见,但是却省事省力的方法:

在设计locator.yaml文件是,把字典的键设计成语po页面的类同名即可。

在基类中封装一下:

import timeimport os.pathfrom utils.handle_logs import loggerfrom utils.handle_path import screenshot_path, config_pathfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.support.wait import WebDriverWaitfrom utils.handle_yaml import get_yaml_datafrom common.myDriver import Driverclass BasePage:def __init__(self): # 调用basepage 需要的浏览器对象,默认谷歌浏览器self._driver = Driver().get_driver()# --------------获取所有需要的定位的元素参数,且实现对号入座# loginpage-----只获取loginPage# [self.__class__.__name__]获取到对应的类的名字,yaml定位元素时命名与后续页面操作类的名字保持一样locator = get_yaml_data(config_path + r'\locator.yaml')[self.__class__.__name__] # 字典# print(locator)for k, v in locator.items(): # k自定义键名,v(定位方法,定位表达式)setattr(self, k, v)"""setattr(self, k, v)1、self是页面的实例2、使用set attrbute--setattr3、创建self这个实例的新的属性,将v赋值给她,self.k = v例子:class Test:passtest = Test() 创建实例#对实例再创建属性,并将对应属性的值赋给它setattr(test, 'name', '123')print(test.name)结果就是test.name = 123"""

------------------------**注**-----------------------------

上述locator的封装方式就是通过[self.__class__.__name__]获取到对应po页面的本身类的名字

locator = get_yaml_data(config_path + r'\locator.yaml')[self.__class__.__name__] # 字典格式

例如登录的定位元素打印出来是:

所以对字典处理:setattr方法将键值和self绑定

for k, v in locator.items(): # k自定义键名,v(定位方法,定位表达式)setattr(self, k, v)

则,self.k = v,则最终可以获取[‘id’, ‘username’],也就是我们需要的,定位方法和定位方式

基类封装中可以直接使用self.自定义键名

find_element(定位方式,定位表达式) ==find_element(self.自定义键名)

则优化后登录页面可以写成:

from pageObjcets.homePage import HomePagefrom common.basePage import BasePagefrom configs.config import urlfrom time import sleep# 登录类,继承基类class LoginPage(BasePage):def to_loginPage(self):self._driver.get(url) # 打开登录页面return self# 1、登录def login(self, username, pwd):# 输入账号self.username_input:优化后的方法self.input_text(self.username_input, username, action='输入账号')# 输入密码self.input_text(self.pwd_input, pwd, action="输入密码")# 点击登录按钮"self.login_btn"就是优化后的使用方法self.click(self.login_btn, action="点击登录按钮")sleep(2)if __name__ == '__main__':# # 登录页面homepage = LoginPage().to_loginPage().login('xxx', 'xxx')# 首页展示# # print('这个类的名字是', LoginPage().__class__.__name__)

这样的话,整个测试框架中看不到定位:只需要配置locator.yaml即可。后续保持键与各个page的类名一样即可。

-------------------------------.----------------------------------

6、测试用例yaml

data文件夹下新建一个文件loginData.yaml

登录的的测试用例编写格式:

# 登录成功用例- ['usernamexxx','pswxxx'] # 账号密码正确--- #分隔符# 登录失败用例- [['xpath',"//*[contains(text(),'该用户不存在!')]"],'该用户不存在!','usernamexx','pswxxx']- [['xpath',"//*[contains(text(),'输入的密码错误!')]"],'输入的密码错误!','usernamexx','pswxxx']- [['xpath',"//*[contains(text(),'该用户不存在!')]"],'该用户不存在!','','111111']- [['css selector','.el-form-item__error'],'The password can not be less than 5 digits','xxxx','']- [['css selector','.el-form-item__error'],'The password can not be less than 5 digits','','']

用例编写完,需要进一步处理数据成为自己想要的:[(‘username’,‘pwd’),(‘us’,‘pwd’),(‘usme’,‘wd’)]这种格式的,就可以使用pytest.mark.parametrize()参数化了。

在utile包新建一个handle_yaml.py文件,因为之前处理定位yaml有了,就在当前文件下封装个读取用例的get_case_yaml函数:因为我们把正向用例和反向用例写在一个yaml文件里,分隔成两个yaml文件数据了,需要单独处理

def get_case_yaml(filedir):caselist = []# 1、打开文件fo = open(filedir, 'r', encoding='utf-8')# 2、读取文件testcases = yaml.load(fo, Loader=yaml.FullLoader)for one in testcases:caselist.append(one)return caselist# print(testcases)

test_login.py提取数据时需要使用角标提取就行了:

get_case_yaml(filedir[0]),提取的就是正确的密码和账号

get_case_yaml(filedir[1]),提取反向用例的数据

7、pytest测试模块+allure测试报告输出

testCase包下新建一个文件test_login.py

1、参数化测试用例:@pytest.mark.parametrize('username, pwd', get_yamlData(testcase_path+r'\loginData.yaml'))

2、优化测试报告:

标题level: ---------------------测试步骤:

@allure.epic() -----------------with allure.step(’ ‘):

@allure.feature()--------------

@allure.story()

@allure.title()

测试报告输出:标红的部分

pytest.main([‘test_login.py’, '--alluredir', reports_path, '--clean-alluredir'])

os.system(f'allure serve {reports_path}')

3、测试报告版本展示:

在reports/tmp下新建一个文件:environment.properties文件,也就是在你生成报告的路径下新建这个文件

里面填写你测试软件平台的版本信息,丰富allure测试报告的展示

Browser=ChromiumBrowser.Version=21.1.18Stand=testpython.Version=3.9.2allure.version=2.13.3

pytest测试代码如下:

import os, pytest, allurefrom utils.handle_yaml import get_yamlDatafrom pageObjcets.loginPage import LoginPagefrom utils.handle_path import testcase_path, reports_pathloginData = f"{testcase_path}/login_cases.yaml"@allure.epic('登录模块test')@allure.story('登录模块test')class TestLogin: # 测试类@pytest.mark.parametrize('username, pwd',get_case_yaml(loginData)[0])@allure.title('登录成功case')def test_login(self, username, pwd):#第一步:输入账户密码登录with allure.step('输入账户密码执行登录'):# 1/登录homepage = LoginPage().to_loginPage().login(username, pwd)# 2/登录是否成功,断言四否具有首页元素。assert断言失败后就无法继续执行。# assert homepage.element_is_presence(homepage.home_button)# 2/解决方案:assume断言失败后可以继续执行下一步,有时间也需要反向的用例测试失败可以继续下一步执行# 第2步:验证登录成功with allure.step('验证登录是否成功'):pytest.assume(homepage.element_is_presence(homepage.home_button,action='登录后验证首页'))# 第3步:退出返回到登录页面,方便后续的反向用例执行with allure.step('退出返回到登录页面'):# 3/做完登录退回到登录页面homepage.to_login_page(action='退出登录')if __name__ == '__main__':pytest.main(['-sq', 'test_login.py', '--alluredir', reports_path, '--clean-alluredir'])os.system(f'allure serve {reports_path}')

验证首页元素,需要先在projectPage页新建一个homePage.py文件,因为首页不属于登录页,需要写在首页中:

# 点击回到首页def homepage(self):self.click(self.home_button, '点击首页')

homepage.element_is_presence(homepage.home_button,action='登录后验证首页'))中的home_button即是首页元素。

反向用例处理:

测试反向用例若使用assert,断言失败就无法继续执行:

引入新的插件:assume

需要安装pytest-assume库,在pycharm终端使用命令安装:

pip3 install pytest-assume

引自:/weixin_50829653/article/details/113179401

反向用例准备好了,在test_login.py再封装一个函数处理反向测试场景:

1、在locator.yaml准备好相应的登录失败的提示文本的元素定位:

2、编写处理反向用例代码

# 执行反向用例,登录失败的场景@pytest.mark.parametrize('locator, expected, username, password',get_case_yaml(loginData)[1])# @pytest.mark.skip(reason='先不跑')@allure.title('登录失败用例')def test_loginerr(self, locator, expected, username, password):with allure.step('执行登录'):homepage = LoginPage().login_page()homepage.login(username, password)with allure.step('断言登录失败提示'):pytest.assume(homepage.get_text(locator) == expected)# homepage.get_screenshot('报错截图')

四个参数分别对应用例中的定位元素(locator),期望结果(expected),账号和密码

通过BasePage的get_text方法获取登录失败提示文本信息,与期望对比,这里使用assert也行,建议使用assume,不然失败了就停止测试了。

通过装饰器mark.skip()选择是否跑反向用例

最后合起来的pytest执行脚本:

import os, pytest, allurefrom utils.handle_yaml import get_yamlDatafrom pageObjcets.loginPage import LoginPagefrom utils.handle_path import testcase_path, reports_pathloginData = f"{testcase_path}/login_cases.yaml"@allure.epic('登录模块test')@allure.story('登录模块test')class TestLogin: # 测试类@pytest.mark.parametrize('username, pwd',get_case_yaml(loginData)[0])@allure.title('登录成功case')def test_login(self, username, pwd):#第一步:输入账户密码登录with allure.step(' 1、输入账户密码执行登录'):# 1/登录homepage = LoginPage().to_loginPage().login(username, pwd)# 2/登录是否成功,断言四否具有首页元素。assert断言失败后就无法继续执行。# assert homepage.element_is_presence(homepage.home_button)# 2/解决方案:assume断言失败后可以继续执行下一步,有时间也需要反向的用例测试失败可以继续下一步执行# 第2步:验证登录成功with allure.step('2 、验证登录是否成功'):pytest.assume(homepage.element_is_presence(homepage.home_button,action='登录后验证首页'))# 第3步:退出返回到登录页面,方便后续的反向用例执行with allure.step(' 3、退出返回到登录页面'):# 3/做完登录退回到登录页面homepage.to_login_page(action='退出登录')# 执行反向用例,登录失败的场景@pytest.mark.parametrize('locator, expected, username, password',get_case_yaml(loginData)[1])# @pytest.mark.skip(reason='先不跑')@allure.title('登录失败用例')def test_loginerr(self, locator, expected, username, password):with allure.step('1、执行登录'):homepage = LoginPage().login_page()homepage.login(username, password)with allure.step('2、断言登录失败提示'):pytest.assume(homepage.get_text(locator) == expected)# homepage.get_screenshot('报错截图')if __name__ == '__main__':pytest.main(['-sq', 'test_login.py', '--alluredir', reports_path, '--clean-alluredir'])os.system(f'allure serve {reports_path}')

8、PO模式结合fixture的数据清除与格式化

testCase包下新建一个conftest.py注:命名必须为conftest.py, pytest的规则命名。只有conftest才能识别

"""scope指的是fixture的作用域:4种:function(函数)<class(类)<module(模块级别)<session(包)auto1、手动调用执行2、自动执行"""import pytestfrom time import sleepfrom common.myDriver import Driver@pytest.fixture(scope='session', autouse=True)def start_running():print("------开始运行UI自动化测试-----")yield# 自动化完成之后,关闭浏览器进程sleep(3) #避免浏览器关闭太快,最后一部操作了但响应时间时浏览器关闭太快导致问题。Driver().get_driver().quit()print("-----结束-UI自动化测试-----")

--------------------**注**--------------------------

1、sleep(3)是为了保证关闭退出浏览器过快而报错。有时候最后一步执行操作未完成就关闭了浏览器。

2、关于数据清除:例如在增加设置或者新增数据时,保证不改变别人的数据,我们只删除自己的数据,一般处理代码放在执行完成测试后:以下非登录模块的数据清除代码。删除代码编写在page模块中调用。

# 1、测试完毕删除测试数据homepage.to_product_list().delete_first_product()# 2、回到首页方便后续执行测试homepage.to_home_page()

放置位置如下:

本地一键执行所有测试模块

run.bat的创建:

本地项目的路径下创建一个run.bat文件

在文件内使用如下:

cd到测试路径->pytest执行所有文件,->输出allure报告

cd ./testCase_pollypytest -sv --alluredir ./outFiles/reports/tmp --clean-alluredirallure serve ./outFiles/reports/tmp

操作汇总

1:需要主要的是操作导致刷新页面需要重新获取定位元素,否则会失效

2:若操作会导致切换页面,需要加一定强制等待sleep(3),不然很容易导致定位报错或者定位不到

3:conftest 的fixture配置退出浏览器或者结束关闭浏览器需要强制等待sleep(5),不然最后一步的执行可能会报错

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。