Python 官方文档:入门教程 => 点击学习
一. 演示项目源码 https://gitee.com/giteetangll/playwright-demo 二、UI自动化分层设计 Auth:登录认证保存后的认证信息 BasePage:封装pl
https://gitee.com/giteetangll/playwright-demo
Auth:登录认证保存后的认证信息
BasePage:封装playwright的基础方法
BuildInLibrary:环境变量存放文件夹,可进行用例参数关联
Common:存放公共方法抽离文件夹
Config:配置文件存放文件夹
Logs:存放断言失败的记录
Pages:存放页面对象文件
TestCases:存放测试用例
TestDatas:存放测试数据
TestFiles:存放测试需要使用的文件
TestReport:存放测试报告
Utils:存放工具的封装
runner.py:项目运行文件
pytest.ini :pytest配置文件
封装常用的元素方法,后续可以自定义日志输出
# -*- coding:utf-8 -*-"""describe:Author:tangEmail:tangllyx@163.comTime: 2023/4/18"""from playwright.sync_api import expect, Pagefrom BuildInLibrary.BuildInLibrary import BuildInLibraryclass BasePage: def __init__(self, page: Page): self.page = page def _Goto_url(self, url): """打开网页""" self.page.goto(url) def _click(self, locator, frame_locator=None): """ 点击元素 :param locator: 传入元素定位器 :param frame_locator: 传入frame框架的的定位器,如果没有传入,则一般点击 :return: """ try: if frame_locator is not None: self.page.frame_locator(frame_locator).locator(locator).click() else: self.page.click(locator) except Exception as e: print(e) def _fill(self, locator, value, frame_locator=None): """ 定位元素,输入内容 :param locator:传入元素定位器 :param value:传入输入的值 :param frame_locator: 传入frame框架 :return: """ value = BuildInLibrary().repalce_parameter(value) try: if frame_locator is not None: self.page.frame_locator(selector=frame_locator).locator(selector_or_locator=locator).fill(value) else: self.page.fill(selector=locator, value=value) except Exception as e: print(e) def _type(self, locator, value, frame_locator=None): """ 模拟人工输入,一个键一个键的输入 :param locator:传入元素定位器 :param value:传入输入的值 :param frame_locator: 传入frame框架 :return: """ value = BuildInLibrary().repalce_parameter(value) try: if frame_locator is not None: self.page.frame_locator(selector=frame_locator).locator(selector_or_locator=locator).type(text=value,delay=100) else: self.page.type(selector=locator, text=value,delay=100) except Exception as e: print(e) def _ele_to_be_visible(self, locator): """断言元素可见""" return expect(self.page.locator(locator)).to_be_visible() def _ele_is_checked(self,selector): """判断元素是否被选选中""" return self.page.is_checked(selector) def _browser_operation(self, reload=False, forward=False, back=False): """浏览器操作,reload 刷新,forward 前进,back 后退""" if reload: self.page.reload() if back: self.page.go_back() if forward: self.page.go_forward() def screenshot(self, path, full_page=True, locator=None): """截图功能,默认截取全屏,如果传入定位器表示截取元素""" if locator is not None: self.page.locator(locator).screenshot(path=path) return path self.page.screenshot(path=path, full_page=full_page) return path
设计想法是为了实现用例关联参数,设置和替换环境变量。
# -*- coding:utf-8 -*- """describe:设置全局环境变量Author:tangEmail:tangllyx@163.comTime: 2023/4/19 """import random, time, reclass BuildInLibrary(): glob_parameter = {} # 存全局变量 def set_glob_parameter(self, key, value): """把value的值放入变量名 key 中,""" # 1.提取 key ##{{first_phone}} parameter_key = re.fullmatch(r'{{(\w+)}}', key).group(1) # 2.保存参数 self.glob_parameter[parameter_key] = value return self.glob_parameter.get(parameter_key) def get_glob_parameter(self, key): self.glob_parameter['timestamp'] = str(int(time.time() * 1000)) self.glob_parameter["timetime"] = str(int(time.time())) self.glob_parameter['random_phone'] = "1" + \ str(random.randint(3, 9)) + \ str(random.randint(0, 9)) + \ time.strftime('%d%H%M%S') return self.glob_parameter.get(key) def repalce_parameter(self, text): """替换参数--> 可以替换多个~,满足{{$参数}}规则的会被替换""" parameter_key = re.findall(r'{{\$(\w+)}}', text) for param in parameter_key: value = self.get_glob_parameter(param) to = rf"{value}" text = re.sub(rf'{{{{\${param}}}}}', lambda m: to, text) return textif __name__ == "__main__":pass
设计想法是为了将常用公共代码进行抽离,使测试脚本更加简洁方便
# -*- coding:utf-8 -*- """describe:allure常用方法抽离,截图方法实现Author:tangEmail:tangllyx@163.comTime: 2023/4/18"""import os.path, allure, pytest, functoolsfrom Config.Config import ConfiGClass PrettyAllure(object): @claSSMethod def PrettyAllureCase(cls, page, CaseData): allure.dynamic.feature(CaseData.get("模块")) allure.dynamic.story(CaseData.get("功能")) allure.dynamic.severity(CaseData.get("优先级")) allure.dynamic.title(f'{CaseData.get("用例编号")}_{CaseData.get("用例标题")}') if CaseData.get("是否执行") != "Y": allure.dynamic.description("用例指定跳过") pytest.skip("用例指定跳过") @classmethod def PrettyAllureScreenShot(cls, page, CaseData): filename = os.path.join(Config.test_screenshot_dir, f"{CaseData.get('用例标题')}.png") page.screenshot(path=filename) allure.attach.file(source=filename, name=CaseData.get('用例标题'), attachment_type=allure.attachment_type.PNG) @classmethod def PrettyAllureWarpper(cls, func): """装饰器函数""" @functools.wraps(func) def inner(*args, **kwargs): # 添加用例信息 cls.PrettyAllureCase(page=kwargs.get("page"), CaseData=kwargs.get("CaseData")) # 如何获取case_data? r = func(*args, **kwargs) # 运行用例 # 添加截图 cls.PrettyAllureScreenShot(page=kwargs.get("page"), CaseData=kwargs.get("CaseData")) return r return innerif __name__ == '__main__': pass
设计思路是为了实现配置化,方便管理,为后续持续集成铺垫。比如:URL配置,日志的配置,邮件服务配置,企业微信聊天机器人配置等
# -*- coding:utf-8 -*- """describe:配置文件Author:tangEmail:tangllyx@163.comTime: 2023/4/17 Software: PyCharm"""import osclass Config: # 项目地址 url = "Http://124.223.40.245:83" # 项目根目录 root_dir = os.path.split(os.path.split(__file__)[0])[0] test_cases_dir = root_dir + os.path.sep + "TestCases" test_files_dir = root_dir + os.path.sep + "TestFiles" test_datas_dir = root_dir + os.path.sep + "TestDatas" test_report_dir = root_dir + os.path.sep + "TestReport" + os.path.sep + "AllureReport" test_result_dir = root_dir + os.path.sep + "TestReport" + os.path.sep + "AllureResult" test_screenshot_dir = root_dir + os.path.sep + "TestReport" + os.path.sep + "Screenshot" logs = root_dir + os.path.sep + "Logs" # 权限认证目录 auth_dir = root_dir + os.path.sep + "Auth" #浏览器 browser = "chrome"if __name__ == '__main__': print(Config.root_dir) print(Config.test_cases_dir)
设计思路是存放日志文件的目录,目前只会记录断言失败的用例信息和数据
TestCases/Test_login.py::TestLogin::test_login[CaseData0] ({'用例编号': 'Login01', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '密码错误登录失败', '前置登录': {'username': 'admin', 'passWord': '123456'}, '账号': '13800138006', '密码': '1234567', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.PHP/Home/user/login.html', '断言元素定位': '//div[text()="密码错误!"]'})TestCases/Test_login.py::TestLogin::test_login[CaseData0] ({'用例编号': 'Login01', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '密码错误登录失败', '前置登录': {'username': 'admin', 'password': '123456'}, '账号': '13800138006', '密码': '1234567', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': '//div[text()="密码错误!"]'})TestCases/Test_login.py::TestLogin::test_login[CaseData0] ({'用例编号': 'Login01', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '密码错误登录失败', '前置登录': {'username': 'admin', 'password': '123456'}, '账号': '13800138006', '密码': '1234567', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': '//div[text()="密码错误!"]'})TestCases/Test_login.py::TestLogin::test_login[CaseData0] ({'用例编号': 'Login01', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '密码错误登录失败', '前置登录': {'username': 'admin', 'password': '123456'}, '账号': '13800138006', '密码': '1234567', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': '//div[text()="密码错误!"]'})TestCases/Test_login.py::TestLogin::test_login[CaseData1] ({'用例编号': 'Login02', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '登录成功', '前置登录': {'username': 'admin', 'password': '123456'}, '账号': '13800138006', '密码': '1234568', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': 'a[title = "退出"]'})TestCases/Test_login.py::TestLogin::test_login[CaseData1] ({'用例编号': 'Login02', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '登录成功', '前置登录': {'username': 'admin', 'password': '123456'}, '账号': '13800138006', '密码': '1234568', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': 'a[title = "退出"]'})TestCases/Test_login.py::TestLogin::test_login[CaseData1] ({'用例编号': 'Login02', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '登录成功', '前置登录': {'username': 'admin', 'password': '123456'}, '账号': '13800138006', '密码': '1234568', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': 'a[title = "退出"]'})TestCases/Test_login.py::TestLogin::test_login[CaseData1] ({'用例编号': 'Login02', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '登录成功', '前置登录': {'username': 'admin', 'password': '123456'}, '账号': '13800138006', '密码': '1234568', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': 'a[title = "退出"]'})TestCases/Test_ReGISter.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Login.py::TestLogin::test_login[CaseData0] ({'用例编号': 'Login01', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '密码错误登录失败', '账号': '13800138006', '密码': '1234567', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': '//div[text()="密码错误!"]'})Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Login.py::TestLogin::test_login[CaseData0] ({'用例编号': 'Login01', '模块': '用户', '功能': '登录', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '密码错误登录失败', '账号': '13800138006', '密码': '1234567', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/login.html', '断言元素定位': '//div[text()="密码错误!"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})TestCases/Test_Register.py::TestRegister::test_register[CaseData0] ({'用例编号': 'Register01', '模块': '用户', '功能': '注册', '优先级': 'blocker', '是否执行': 'Y', '用例标题': '注册成功', '用户名': '{{$random_phone}}', '密码': '123456', '确认密码': '123456', '验证码': '8888', 'url地址': 'http://124.223.40.245:83/index.php/Home/user/reg.html', '断言元素定位': 'a[title="退出"]'})
设计思路是为了存放页面对象,每个页面单独进行存放,页面属性和行为与用例和数据区分,便于后期维护
# -*- coding:utf-8 -*-"""describe:登录页面Author:tangEmail:tangllyx@163.comTime: 2023/4/17Software: PyCharm"""import allurefrom BasePage.BasePage import BasePageclass LoginPage(BasePage): # 元素定位器 __username = "#username" __password = "#password" __verify_code = "#verify_code" __login_button = 'a[name="sbtbutton"]' __button_logout = 'a[title="退出"]' @allure.step("打开登录页面") def goto_login(self, url): self._goto_url(url) @allure.step("输入账号") def fill_username(self, value): self._fill(self.__username, value) @allure.step("输入密码") def fill_password(self, value): self._fill(self.__password, value) @allure.step("输入验证码") def fill_verify_code(self, value): self._fill(self.__verify_code, value) @allure.step("点击登录按钮") def click_login_button(self): self._click(self.__login_button) @allure.step("点击安全退出按钮") def click_button_logout(self): self._click(self.__button_logout) def browser_operation(self, reload=True, forward=False, back=False): self._browser_operation(reload=reload, forward=forward, back=back)
# -*- coding:utf-8 -*- """describe:注册页面Author:tangEmail:tangllyx@163.comTime: 2023/4/20 """import allurefrom BasePage.BasePage import BasePageclass RegisterPage(BasePage): __username = "#username" __verify_code = 'input[placeholder="图像验证码"]' __password = "#password" __password2 = "#password2" __checktxt = "#checktxt" __btn_agree = ".regbtn.J_btn_agree" @allure.step("前往注册页面") def goto_register(self, url): self._goto_url(url) @allure.step("输入用户名") def type_username(self, username): self._type(self.__username, username) @allure.step("输入验证码") def type_verify_code(self, verify_code): self._type(self.__verify_code, verify_code) @allure.step("输入密码") def type_password(self, password): self._type(self.__password, password) @allure.step("输入确认密码") def type_password2(self, password2): self._type(self.__password2, password2) @allure.step("勾选同意") def click_checktxt(self): if not self._ele_is_checked(self.__checktxt): self._click(self.__checktxt) @allure.step("点击同意注册按钮") def click_btn_agree(self, ): self._click(self.__btn_agree) @allure.step("点击断言元素") def click_ele(self,locator): self._click(locator)
设计思路是为了存放测试用例,使得用例和页面对象分开。维护时,只需要去维护page层即可
import allure, osimport pytestfrom Pages.LoginPage.LoginPage import LoginPagefrom Pages.MyAccountPage.MyAccountPage import MyAccountPagefrom Utils.ReadYaml import ReadYamlfrom Common.AllurePretty import PrettyAllurefrom Config.Config import Configclass TestLogin: @pytest.mark.run(order=1) @PrettyAllure.PrettyAllureWarpper @pytest.mark.parametrize("CaseData", ReadYaml(os.path.join(Config.test_datas_dir, "TestLoginData.yaml")).read()) def test_login(self, page, CaseData: dict): new_page = LoginPage(page) # PrettyAllure(page, CaseData).PrettyAllureCase() new_page.goto_login(CaseData["url地址"]) new_page.fill_username(CaseData["账号"]) new_page.fill_password(CaseData["密码"]) new_page.fill_verify_code(CaseData["验证码"]) new_page.click_login_button() MyAccountPage(page).logout_to_be_visible(CaseData["断言元素定位"])
# -*- coding:utf-8 -*- """describe:注册用例Author:tangEmail:tangllyx@163.comTime: 2023/4/20 """import timeimport allure, osimport pytestfrom Pages.LoginPage.LoginPage import LoginPagefrom Pages.RegisterPage.RegisterPage import RegisterPagefrom Pages.MyAccountPage.MyAccountPage import MyAccountPagefrom Utils.ReadYaml import ReadYamlfrom Common.AllurePretty import PrettyAllurefrom Config.Config import Configclass TestRegister: @pytest.mark.smoking @pytest.mark.run(order=0) @PrettyAllure.PrettyAllureWarpper @pytest.mark.parametrize("CaseData", ReadYaml(os.path.join(Config.test_datas_dir, "TestRegisterData.yaml")).read()) def test_register(self, page, CaseData: dict): rp = RegisterPage(page) rp.goto_register(url=CaseData["url地址"]) rp.type_username(username=CaseData["用户名"]) rp.type_verify_code(CaseData["验证码"]) rp.type_password(CaseData["密码"]) rp.type_password2(CaseData["确认密码"]) rp.click_checktxt() rp.click_btn_agree() MyAccountPage(page).logout_to_be_visible(CaseData["断言元素定位"]) rp.click_ele(CaseData["断言元素定位"])
设计思路是为了存放业务数据,使数据和业务区分开来,实现数据驱动
- 用例编号: Register01 模块: 用户 功能: 注册 优先级: blocker 是否执行: Y 用例标题: 注册成功 用户名: "{{$random_phone}}" 密码: "123456" 确认密码: "123456" 验证码: "8888" url地址: /index.php/Home/user/reg.html 断言元素定位: a[title="退出"]- 用例编号: Register02 模块: 用户 功能: 注册 优先级: blocker 是否执行: Y 用例标题: 两次输入的密码不一致,注册失败 用户名: "{{$random_phone}}" 密码: "123456" 确认密码: "123456789" 验证码: "8888" url地址: /index.php/Home/user/reg.html 断言元素定位: .layui-layer-content.layui-layer-padding- 用例编号: Register03 模块: 用户 功能: 注册 优先级: blocker 是否执行: Y 用例标题: 重读手机号,注册失败 用户名: "13811111111" 密码: "123456" 确认密码: "123456" 验证码: "8888" url地址: /index.php/Home/user/reg.html 断言元素定位: .layui-layer-content.layui-layer-padding
设计思路是为了单独存放测试业务的所需文件
设计思路是为了存放测试报告、测试数据和测试据图的
设计思路是为了存放常用工具的封装,比如excel文件读写,yaml文件读写,数据库操作等
# -*- coding:utf-8 -*- """describe:读取yaml文件Author:tangEmail:tallyx@163.comTime: 2023/4/17 Software: PyCharm"""import yaml, osfrom Config.Config import Configclass ReadYaml(object): def __init__(self, filename): self.filename = filename def read(self): with open(file=self.filename, mode="r", encoding='utf8', ) as f: data = f.read() data_yaml = yaml.load(data, Loader=yaml.FullLoader) for value in data_yaml: value["url地址"] = Config.url + value["url地址"] return data_yamlif __name__ == '__main__': pass
pytest配置文件
[pytest]# 配置pytest命令行运行参数# 空格分隔,可添加多个命令行参数 -所有参数均为插件包的参数# addopts = -s# 配置测试搜索的路径# 当前目录下的TestCases文件夹 -可自定义testpaths = ./TestCases# 配置测试搜索的文件名# 当前目录下的testcase文件夹下,以test_开头,以.py结尾的所有文件 -可自定义python_files = test_*.py *_test.py# 配置测试搜索的测试类名# 当前目录下的testcase文件夹下,以test_开头,以.py结尾的所有文件中,以Test开头的类 -可自定义Python_classes = Test*# 配置测试搜索的测试函数名# 当前目录下的testcase文件夹下,以test开头,以.py结尾的所有文件中,以Test_开头的类内,以test_开头的方法 -可自定义python_functions = test*markers = smoking: 冒烟
项目运行入口文件
import osimport pytestfrom Config.Config import Configif __name__ == '__main__': AllureReport = Config.test_report_dir AllureResult = Config.test_result_dir Screenshot = Config.test_screenshot_dir os.system(f"del {os.path.join(Screenshot,'*.png')}") pytest.main(["-v", "-s", '--reruns=3', f'--alluredir={AllureResult}', "--clean-alluredir"]) os.system(f'allure generate {AllureResult} -o {AllureReport} --clean')
来源地址:https://blog.csdn.net/m0_65028806/article/details/130304167
--结束END--
本文标题: python+playwright+pytest+allure+pom+yaml实现UI自动化测试
本文链接: https://www.lsjlt.com/news/402627.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0