已转战 Playwright node.js 版,不继续使用 Py3 版了
相关示例仓库:https://github.com/tomoyachen/e2e-playwright-scaffold
平时工作一直用的 Cypress,但是 Cypress 真的太慢了,就想看看有什么替代品。Selenium 我一直不太喜欢,正好看到微软出的 Playwright 好像蛮有意思的。虽然 Playwright 的 JS 版本 的 Star 是 Python 版本的十倍之多,不过我个人还是更喜欢 Python 和 Pytest,就还是用 Python 版的 Playwright 搭配 Pytest 来食用了。(其实是 js 不太熟悉 XD)
主流的 UI 自动化 框架对比可以参考这篇文章 [传送门]
本项目风格和我之前写的 api-test比较相似,越小越简单越好。
Github:https://github.com/tomoyachen/playwright-test
本项目参考了虫师 & Yusuke Iwaki 的项目
定位符、页面操作、业务逻辑三层:合并成了 page 类
测试用例层:test 类(基于 pytest)
数据层:yaml 文件 (config 数据 与 fixtures 数据)
结果层:HTML 报告(基于 pytest-html,感兴趣可以改成 allure),Log 日志(暂无)
* 图来自 陈晓伍 的 《Python Web自动化测试设计与实现》
test 类
page @pytest.fixture 来自 pytest-playwright
env 是自定义的 @pytest.fixture,用来读取当前环境的配置信息
使用内置的 browser @pytest.fixture 来 生成一个 page @pytest.fixture
提升作用域,以达到共用同一浏览器的效果
page 类
想了好几种方式,如何来使用page对象。本来想试试继承,但好像不行。
最终还是作为类属性来使用了。
config 数据,管理 base_url 等通用信息
fixtures 数据,就是测试用例的测试数据了,只是我习惯 Cypress 的命名方式了。
fixtures 我定义了2种获取方式。
一种是test 类中获取当前要用的测试对象的 yaml 文件
# test 类
@pytest.fixture()
def fixtures(self):
yield Tools.get_fixtures("baidu_search")
# ---- 用法 -----
# test 类
fixtures['kerwords']
一种是放在conftest.py中,作为@pytest.fixture 来用
# conftest.py
@pytest.fixture(scope="class")
def fixtures():
def _fixtures(filename: str):
from common.tools import Tools
return Tools.get_fixtures(filename)
yield _fixtures
# ---- 用法 -----
# test 类
fixtures('baidu_search')['kerwords']
conftest.py 文件中,pytest 钩子和 pytest-html 钩子都有详尽的注解
Playwright 内置的视频录制,传入一个 路径就可以了。
还学到了一个新钩子
@pytest.fixture(scope="session")
def browser_context_args(browser_context_args, tmpdir_factory: pytest.TempdirFactory):
return {
**browser_context_args,
"record_video_dir": os.path.join(OUTPUT_DIR, "videos")
}
在 feature/allure 分支
有了截图和视频,再看 pytest-html 就有点磕碜了。所以就接了 allure。
目前是pytest-html 和 allure部分都保留了。
config 数据 和 fixtures 数据如何整合,目前还在思考
Tools.get_config()、Tools.get_fixtures() 等依赖 env 信息的操作,只能放在__init__ 或 实例方法中。因为引入文件时会自动执行文件。此时还没有 env 信息,所以会报错。
# 错误
class BaiduSearchPage:
host = Tools.get_config("base_url")
def __init__(self, page: Page):
self.page = page
# 正确
class BaiduSearchPage:
def __init__(self, page: Page):
self.page = page
self.host = Tools.get_config("base_url")