iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python+playwright+pytest+allure+pom+yaml实现UI自动化测试
  • 912
分享到

python+playwright+pytest+allure+pom+yaml实现UI自动化测试

pythonpytest开发语言 2023-09-10 21:09:09 912人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

一. 演示项目源码 https://gitee.com/giteetangll/playwright-demo 二、UI自动化分层设计 Auth:登录认证保存后的认证信息 BasePage:封装pl

一. 演示项目源码

https://gitee.com/giteetangll/playwright-demo

二、UI自动化分层设计

项目目录
Auth:登录认证保存后的认证信息
BasePage:封装playwright的基础方法
BuildInLibrary:环境变量存放文件夹,可进行用例参数关联
Common:存放公共方法抽离文件夹
Config:配置文件存放文件夹
Logs:存放断言失败的记录
Pages:存放页面对象文件
TestCases:存放测试用例
TestDatas:存放测试数据
TestFiles:存放测试需要使用的文件
TestReport:存放测试报告
Utils:存放工具的封装
runner.py:项目运行文件
pytest.ini :pytest配置文件

三、po设计模型+分层设计思想

3.1BasePage层

封装常用的元素方法,后续可以自定义日志输出

# -*- 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

3.2 BuildInLibrary层

设计想法是为了实现用例关联参数,设置和替换环境变量。

# -*- 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

3.3 Common层

设计想法是为了将常用公共代码进行抽离,使测试脚本更加简洁方便

# -*- 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

3.4 Config层

设计思路是为了实现配置化,方便管理,为后续持续集成铺垫。比如: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)

3.5 Logs层

设计思路是存放日志文件的目录,目前只会记录断言失败的用例信息和数据

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="退出"]'})

3.6 Pages层

设计思路是为了存放页面对象,每个页面单独进行存放,页面属性和行为与用例和数据区分,便于后期维护

# -*- 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)

3.7 TestCases 层

设计思路是为了存放测试用例,使得用例和页面对象分开。维护时,只需要去维护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["断言元素定位"])

3.8 TestDatas 层

设计思路是为了存放业务数据,使数据和业务区分开来,实现数据驱动

-  用例编号: 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

3.8 TestFiles层

设计思路是为了单独存放测试业务的所需文件

3.9 TestReport层

设计思路是为了存放测试报告、测试数据和测试据图的
在这里插入图片描述

3.10 Utils 层

设计思路是为了存放常用工具的封装,比如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  

3.11 pytest.ini 文件

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: 冒烟

3.12 runner.py文件

项目运行入口文件

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文档到电脑,方便收藏和打印~

下载Word文档
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作