【工作记录】UI自动化搭建全程实录:Python、Playwright、Pytest、Allure、YAML与nb_log集成实践

可参考:

使用Playwright+Pytest+Yaml+Allure搭建UI自动化测试用例框架_自动化测试框架playwright allure-CSDN博客

1、UI自动化框架_结构目录及说明

  • Python:核心编程语言,提供基础语法和丰富的第三方库支持。
  • Playwright:浏览器自动化工具,实现跨浏览器网页操作与测试。同Selenium
  • Pytest:测试框架,管理用例、断言及执行,支持扩展插件。
  • Allure:可视化测试报告工具,生成结构化结果便于问题追溯。
  • YAML:配置文件格式,结构化存储测试数据或环境参数。
  • nb_log:Python日志库,提供灵活日志记录与多线程异步输出。
  • AutomatedTesting
    ├─ common                         公共层包
    ├─ logs                                日志文件                  
    ├─ pageElement                  存放页面元素定位文件的文件夹目录
    ├─ testdata                           测试用例数据
    ├─ testScripts                       测试用例                                          
    ├─ util                                   工具
    ├─ create_tree_with_args.py   用于生成指定目录结构树
    ├─ nb_log_config.py               日志模板配置脚本文件
    ├─ README.md                     ReadMe
    └─ requirements.txt                依赖包及其精确的版本号 

    README.md

    AutomatedTesting
    ├─ common                                                   公共层包目录  
    │   ├─ page_action.py                                       封装常用页面组件的操作方法脚本
    │   └─ __init__.py
    ├─ logs                                                     存放所有自动化测试用例的运行日志文件夹目录                     
    │   ├─ 20231120.log                                         一个log文件代表一天中所有的日志
    │   └─ 20231121.log
    ├─ pageElement                                              存放页面元素定位文件的文件夹目录
    │   ├─ ams_main_page_element.yml                            定位文件命名应该能直观看出是代表系统中哪一个页面
    │   ├─ login_page_element.yml
    │   └─ main_page_element.yml
    ├─ testdata                                                 存放测试用例运行中输入的数据的文件夹目录
    │   └─ login_test_data.yml                                  数据文件命名要能直观看出是用于哪个模块的测试用例
    ├─ testScripts                                              存放测试用例脚本的包目录                                                 
    │   ├─ allure-report                                        所有测试用例的运行结果报告文件夹--结果统计报告是html格式
    │   ├─ allure_result                                        所有测试用例的运行结果数据文件夹--结果数据文件是json格式
    │   ├─ test-results                                         存放所有测试用例运行结果的截图和录屏数据
    │   ├─ conftest.py                                          主要用来定义一些fixture前后置方法
    │   ├─ run.py                                               运行项目中所有测试用例并生成报告
    │   ├─ test_iotdevicelist.py                                测试用例--命名规则必须以“test”开头
    │   ├─ test_mainpagefunc.py
    │   └─ __init__.py
    ├─ util                                                     定义实用工具的包目录
    │   ├─ dirAndTime.py                                        获取当前时间和获取当前日期
    │   ├─ handle_logging.py                                    生成运行日志
    │   ├─ handle_yaml.py                                       读取yml格式文件中的数据
    │   └─ __init__.py
    ├─ create_tree_with_args.py                                 用于生成指定目录结构树
    ├─ nb_log_config.py                                         日志模板配置脚本文件
    ├─ README.md                                                ReadMe
    └─ requirements.txt                                         用于记录所有依赖包及其精确的版本号,以便新环境部署

    2、安装软件库

    1. 安装python

    如果你的电脑已经装有python且是3.8以上版本请跳过本章

    打开浏览器并访问Python官网,下载windows版安装程序:https://www.python.org

    下载好安装包后,右击“以管理员身份运行”,在安装对话框中勾选“Add python.exe to PATH”,选择“Customize installation”来自定义一个python安装路径注意:安装路径中不要有中文目录,需要所有目录是纯英文的),选择好安装路径后点击[Install]

    安装完成后,点击“禁用路径长度限制”,然后点击[关闭]

    再单击[关闭]按钮,即可结束安装

    校验是否安装成功:使用快捷键“WIN+R”打开运行窗口,输入“cmd”,单击[确定]打开命令窗口,输入命令“python –version”(有的windows系统输入“python -V”),会看到安装的python版本号输出,这个时候就说明完全安装好了。

    2. 安装Pycharm(社区版)

    打开浏览器访问Pycharm官网:

    Download PyCharm: The Python IDE for data science and web development by JetBrains

    下载完毕后,根据安装向导安装即可:

    选择安装路径,注意:安装路径中不要有中文目录,需要所有目录是纯英文的

    建议全部勾选

    点击install

    安装完成后点击Finish

    这时候桌面已经有pycharm快捷方式,双击快捷方式,打勾并点击继续

    点击加号”+”,创建一个新项目

    选择项目路径,默认C盘,我这里自定义选择,选择完毕后,最后点击Create

    选择需要运行的.py文件,单击右键-run

    结果如下则表示配置成功

    3. 安装Java、Allure

    1)安装Java

    首先需要下载java开发工具包jdk,下载地址:

    https://www.oracle.com/java/technologies/downloads/archive/,这里显示各种版本的jdk,建议下载1.8及以上的版本

    点进去之后拉最下面选择Windows x64名字开头的安装包下载,下载时需要登录Oracle账户(没有就注册一个)。

    下载完成后右击安装包->使用管理员方式运行,安装过程中可以自定义安装目录并记住安装路径(后面需要使用其配置环境变量)。注意:安装路径中不要有中文目录,需要所有目录是纯英文的

    安装完成后右击“我的电脑”点击“属性”,选择“高级系统设置”

    点击环境变量按钮,打开环境变量编辑窗口,在系统变量区域新建JAVA_HOME变量:

    变量名:JAVA_HOME 变量值:上面的jdk安装路径(绝对路径)

    再新建CLASSPATH变量:变量名:CLASSPATH 变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar

    在系统变量中找到Path变量点击[编辑]按钮,打开编辑环境变量窗口,点击[新建]按钮,在底部增加一个输入框,输入%JAVA_HOME%\bin,再次点击[新建]按钮,再增加一个输入框,输入%JAVA_HOME%\jre\bin

    一路点击[确定]按钮直到关掉所有环境变量设置窗口。配置完成后,右击电脑左下角windows系统图标->“运行”,输入“cmd”,在命令窗口中输入“java”回车

    再输入“java -version”回车

    输入以上命令回车后出现如图所示文字即代表java安装成功。

    2)安装allure

    由于allure需要依赖java环境,所以在上节就说明了jdk安装,接着就要下载allure包并配置环境变量:allure包下载地址:Releases · allure-framework/allure2 · GitHub

    我们下载windows版的zip压缩包即可

    在本地解压下载好的allure包,解压后有4个文件夹,复制bin文件夹目录路径,并用其设置allure环境变量,添加到Path变量中:

    运行“cmd”打开cmd命令窗口,输入:allure –version 出现下图所示版本号即代表安装成功

    4. 安装库

    1. 初步使用
    pip install pyaml
    pip install playwright
    playwright install chromium
    pip install allure-pytest
    pip install pytest
    pip install pytest-playwright
    
    pip install nb_log -i https://mirrors.aliyun.com/pypi/simple  
    
    可选的镜像地址有
    豆瓣           https://pypi.douban.com/simple
    阿里云          https://mirrors.aliyun.com/pypi/simple
    清华大学        https://pypi.tuna.tsinghua.edu.cn/simple
    中国科技大学     https://pypi.mirrors.ustc.edu.cn/simple
    
    
    2. 详细使用

    在本地写一个requirements.txt文本文件,放在上面已创建项目的根目录下,打开cmd命令窗口进入requirements文件所在路径,执行安装第三方库的命令:

    pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

    -i 参数代表从指定镜像源下载

    这个命令的意思是从国内镜像网站下载安装requirements.txt这个文件中所有的库。

    全部下载完成后,在命令窗口输入:pip list 即可看到已经安装好的库名及版本

    然后执行playwright install命令安装自动化运行所需的浏览器,Playwright介绍见官网:Installation | Playwright Python

    建议大家平时多研究playwright官网,官网手册全面且简单易学,使用微软的Edge浏览器访问官网可以翻译成中文。为后续手写测试用例脚本打下基础。

    另一个学习网站:什么是playwright?-playwright-何三笔记

    PS:安装过程中如果一直安装不成功的话,说明你安装的python版本比较高,有些第三方库难以适配到,那么请卸载该python,重新下载安装较低版本的python,推荐3.9\3.10左右的版本。

    3、common公共层包

    1. 浏览器启动方法封装browser_manager.py
    from playwright.sync_api import sync_playwright
    
    class BrowserManager:
        def __init__(self):
            self.playwright=None
            self.browser=None
            self.page=None
    
        def launchChrome(self,headless=False, channel="chrome"):
            """
            launchChrome为无头模式下启动谷歌浏览器
            :param headless:
            :param channel:
            :return:
            """
            self.playwright = sync_playwright().start()
            self.browser = self.playwright.chromium.launch(headless=headless, channel=channel)
            self.page = self.browser.new_page()
            return self.page
    
        def close(self):
            """
            关闭浏览器、关闭playwright
            """
            self.browser.close()
            self.playwright.stop()
    
    # 检验是否可以使用playwright
    # if __name__ == "__main__":
    #     # 使用示例
    #     BrowserManager = BrowserManager()
    #     try:
    #         page =BrowserManager.launchChrome()
    #         # 访问网页并执行操作
    #         page.goto("https://www.baidu.com/")
    #         print("当前标题:", page.title())
    #         page.wait_for_timeout(2000)  # 等待2秒查看效果
    #
    #     finally:
    #         BrowserManager.close()

    4、logs日志文件                  

    1)使用nb_log记录日志,配置logger
    import os
    import time
    import logging
    from nb_log import LogManager
    
    # 获取项目根目录(更可靠的获取方式)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    LOG_DIR = os.path.join(BASE_DIR, 'logs')  # 日志目录定义
    
    # 确保日志目录存在
    os.makedirs(LOG_DIR, exist_ok=True)
    
    def get_logger():
        """单例模式获取 Logger 对象"""
        logger_name = __name__  # 使用模块名作为 Logger 名称
        log_filename = f"{time.strftime('%Y%m%d')}.log"  # 按日期命名日志文件
    
        # 创建 Logger 并配置处理器
        logger = LogManager(logger_name).get_logger_and_add_handlers(
            log_level_int=logging.DEBUG,  # 使用常量提高可读性
            is_add_stream_handler=True,   # 启用控制台输出
            log_path=LOG_DIR,             # 直接使用 LOG_DIR
            log_filename=log_filename,    # 动态生成文件名
            formatter_template=logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
            )
        )
        return logger
    
    # 全局唯一 Logger 实例
    test_log = get_logger()
    
    if __name__ == "__main__":
        # 测试日志输出
        test_log.debug("Debug 信息(测试)")
        test_log.info("Info 信息(测试)")
     2)使用实例
    from util.handle_logging import test_log  # 引入函数
    
    # 特定位置标记插入即可
    test_log.info("成功登录系统")
    test_log.error("登录识别")
    test_log.debug("调试内容")
    test_log.warnning("提示内容")
    
    

    3)报错解决(已安装包,仍提示未安装)

    set PYTHONPATH=项目根目录

    5、pageElement页面元素定位文件

    6、testdata测试用例数据

    7、testScripts测试用例           

    1. 测试用例test_001
    import pytest
    
    
    def test_001(page):
    
        page.goto("https://www.baidu.com/")
        print("当前标题:", page.title())
        page.wait_for_timeout(2000)  # 等待2秒查看效果
    2. 正式用例

    待补充…

                     
    8、util工具包

    9、create_tree_with_args.py   用于生成指定目录结构树

    生成目录说明:运行此脚本,复制控制台打印内容到readme.md即可

    #! -*-conding=: UTF-8 -*-
    # 2023/11/22 9:52
    """
        描述:python实现tree命令
    """
    
    from pathlib import Path
    import argparse
    
    from typing import Optional
    
    # 黑名单 不想列出的目录
    blacklist = [".git", ".idea"]
    
    # ANSI颜色代码
    BLUE = "\033[34m"
    WHITE = "\033[0m"
    
    
    def is_hidden(file: Path) -> bool:
        return file.name.startswith(".")
    
    
    def get_entries(path: Path, show_hidden: bool = False):
        entries = list(path.iterdir())
        if not show_hidden:
            entries = [entry for entry in entries if not is_hidden(entry)]
        return sorted(entries, key=lambda entry: entry.is_file())
    
    
    def print_tree(path: Path, depth: Optional[int], show_hidden: bool = False, indent: str = "", is_last: bool = True):
        entries = get_entries(path, show_hidden)
        total_entries = len(entries)
        for i, entry in enumerate(entries):
            is_dir = entry.is_dir()
            entry_name = entry.name
    
            if i == total_entries - 1:
                branch = "└─ "
                new_indent = indent + "    " if is_last else indent + "│   "
            else:
                branch = "├─ "
                new_indent = indent + "│   "
    
            if is_dir:
                print(f"{indent}{branch}{BLUE}{entry_name}{WHITE}")
                if depth is None or (depth and depth > 1):
                    print_tree(entry, None if depth is None else depth - 1, show_hidden, new_indent, i == total_entries - 1)
            else:
                print(f"{indent}{branch}{entry_name}")
    
    
    def main():
        parser = argparse.ArgumentParser(description="Python实现tree命令")
        parser.add_argument("-p", "--path", type=str, nargs="?", default=".", help="要遍历的目录路径")
        parser.add_argument("-d", "--depth", type=int, help="限制显示的层数")
        parser.add_argument("--hidden", action="store_true", help="显示隐藏文件")
        args = parser.parse_args()
        path = Path(args.path).resolve()
        print(path)
        print_tree(path, args.depth, args.hidden)
    
    
    if __name__ == "__main__":
        # 在终端窗口输入命令:python create_tree_with_args.py -d 3
        # 这个命令表示打印当前工程目录结构,且深度是3层,层数可以自定义
        main()
    

    10、nb_log_config.py日志模板配置脚本文件

    11、README.md

     使用create_tree_with_args.py生成

    12、requirements.txt依赖包及其精确的版本号 

    13、执行命令run.py

    # 控制台执行命令:
    python -m pytest -sv

    集成后执行命令待补充…

    14、fixture初始化、清除- conftest.py

    可参考:

    python3.x中 pytest之fixture – 漂泊的小虎 – 博客园

    fixture是指夹具(把用例夹在中间),它包括前置工作和后置工作,前置是用例代码的准备阶段,后置是用例执行之后的清理阶段,用例是放在前置代码和后置代码

    使用fixture来创建对象,启动浏览器,运行结束后再进行清除

    import pytest
    from common.browser_manager import BrowserManager
    
    @pytest.fixture(scope="function")
    def page():
        """
        函数初始化打开浏览器,函数结束后清除
        初始化、清除分别在前后执行,并且只会执行1次
        :return:
        """
        browser_manager = BrowserManager()
        try:
            browser_page = browser_manager.launchChrome()
            yield browser_page
        finally:
            browser_manager.close()

    15、报错解决

    1.  解决 AttributeError: 'str' object has no attribute 'iter_parents' 的步骤

    问题原因

  • 版本冲突pytest 8.1.0 及以上版本与某些插件(如 allure-pytest 或 pytest-xdist)的兼容性被破坏,导致访问 item.nodeid 时触发 iter_parents 方法缺失的错误31
  • 解决方案:降级 pytest 到兼容版本
    # 卸载当前版本 pip uninstall pytest
    
    # 安装指定兼容版本 pip install pytest==8.0.2

    
    

     

    作者:星光不负赶路人!

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【工作记录】UI自动化搭建全程实录:Python、Playwright、Pytest、Allure、YAML与nb_log集成实践

    发表回复