這是關於playwright系列介紹的最後一篇。搭建基於 playwright 的自動化專案。
GitHub地址: https://github.com/defnngj/playwright-pro
具備功能
關鍵技術:
- pylaywright測試庫
- pytest單元測試框架
- pytest-playwright外掛
非關鍵技術:
- pytest-html外掛
- pytest-rerunfailures外掛
- seldom 測試框架
實現功能:
- 元素定位與操作分離
- 失敗自動截圖並儲存到HTML報告
- 失敗重跑
- 可配置不同的瀏覽器執行
- 可配置
headless/headful
模式 - 實現引數化讀取資料檔案
一個自動化具備的基本功能差不多就這些了。其實主要是使用了一堆框架和外掛,主要是整合能力。
使用方式
- 安裝依賴
$ pip install -r requirements.txt
注:安裝requirements.txt
指定依賴庫的版本,這是經過測試的,有時候新的版本可會有錯。
- 配置
在 config.py
檔案配置
class RunConfig:
"""
執行測試配置
"""
# 執行測試用例的目錄或檔案
cases_path = "./test_dir/test_parametrize.py"
# 配置瀏覽器驅動型別(chromium, firefox, webkit)。
browser = "chromium"
# 執行模式(headless, headful)
mode = "headful"
# 配置執行的 URL
url = "https://www.baidu.com"
# 失敗重跑次數
rerun = "0"
# 當達到最大失敗數,停止執行
max_fail = "5"
- 執行
執行測試
$ python run.py
設計細節
- 關於page object設計模式
page object是自動化測試最常用的設計模式。
但 playwright 中的只提供了操作方法,元素定位
和測試資料
都只是引數。
# 輸入
page.type('#kw', "playwright")
# 點選
page.click('#su')
我們依然,可以將元素定位單獨封裝一層。
class BaiduElem:
search_input = "#kw" # 搜尋框
search_button = "#su" # 搜尋按鈕
settings = "#s-usersetting-top" # 設定
search_setting = "#s-user-setting-menu > div > a.setpref" # 搜尋設定
save_setting = 'text="儲存設定"' # 儲存設定
在測試用例中的使用
from element.baidu_element import BaiduElem
from playwright.sync_api import Page
def test_baidu_search(page: Page, base_url):
"""
"""
page.goto(base_url)
page.type(BaiduElem.search_input, text="playwright")
page.click(BaiduElem.search_button)
sleep(2)
assert page.title() == "playwright_百度搜尋"
這肯定不是什麼好的設計。用例層寫起來會比較囉嗦, 最好可以page.elem.type("playwright")
的語法實現,這就需要在playwright的基礎上再封裝一套API, 看playwright 原始碼還是有些複雜的,主要是用了很多就非同步,成本比較大,暫時先這麼用。
- 關於自動截圖
自動截圖需要 pytest/pytest-html 和 playwright 配合完成, pytest/pytest-html 判斷用例實現,並把圖片插入到報告中。 playwright 實現截圖動作。
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
"""
用於向測試用例中新增用例的開始時間、內部註釋,和失敗截圖等.
:param item:
"""
pytest_html = item.config.pluginmanager.getplugin('html')
outcome = yield
report = outcome.get_result()
report.description = description_html(item.function.__doc__)
extra = getattr(report, 'extra', [])
page = item.funcargs["page"]
if report.when == 'call':
xfail = hasattr(report, 'wasxfail')
if (report.skipped and xfail) or (report.failed and not xfail):
case_path = report.nodeid.replace("::", "_") + ".png"
if "[" in case_path:
case_name = case_path.split("-")[0] + "].png"
else:
case_name = case_path
capture_screenshots(case_name, page)
img_path = "image/" + case_name.split("/")[-1]
if img_path:
html = '<div><img src="%s" alt="screenshot" style="width:304px;height:228px;" ' \
'onclick="window.open(this.src)" align="right"/></div>' % img_path
extra.append(pytest_html.extras.html(html))
report.extra = extra
def capture_screenshots(case_name, page):
"""
配置用例失敗截圖路徑
:param case_name: 用例名
:return:
"""
global driver
file_name = case_name.split("/")[-1]
if RunConfig.NEW_REPORT is None:
raise NameError('沒有初始化測試報告目錄')
else:
image_dir = os.path.join(RunConfig.NEW_REPORT, "image", file_name)
page.screenshot(path=image_dir)
通過page = item.funcargs["page"]
拿到playwright的驅動,截圖判斷邏輯有點複雜,不過我已經實現了。
總結
- playwright還不穩定,我在使用的時候時常報一些錯誤,錯誤日誌也不友好。計劃在正式專案中使用的謹慎考慮,估計有一些坑要踩。
- 不熟悉playwright的API,可以通過官方文件,或者是專案自帶的測試用例,或者閱讀專案原始碼都是很好的學習方式。