pytest-pyppeteer:在pytest中運行pyppeteer

pytest-pyppeteer

pytest-pyppeteer是我寫的一個 pytest 插件,支持在 pytest 中運行pyppeteer,起因是爲了解決工作中的一個測試需求,現在將其開源並做簡單介紹。

背景

爲什麼不用 selenium?

最根本的原因是 selenium 的配置比較繁瑣,最常見的問題是需要保持 webdriver 和瀏覽器版本的一致性。

pyppeteer 的簡單介紹

pyppeteer 是 puppeteer的非官方 python 版本,幾乎實現了和其相同的 API,可以非常方便的去操作 Chrome 瀏覽器。

pyppeteer 的侷限性

目前最明顯的問題是沒有提供跨瀏覽器的解決方案,最新的 puppeteer 已經提供對 Firefox 的支持,但是 pyppeteer 可能還需要一些時間。

安裝

推薦使用pipenv管理虛擬環境,並替換爲國內 pip 源。

$ pipenv install pytest-pyppeteer

僅支持 python >= 3.7

快速開始

用下面這個測試用例來說明:斷言電影《活着》的豆瓣評分大於 9.0。

from dataclasses import dataclass

from pytest_pyppeteer.models import Browser


@dataclass(init=False)
class Elements:
    """收集所有使用到的頁面元素,可以爲 XPath 或者 CSS Selector。"""

    # 查詢輸入框
    query = "#inp-query"

    # 點擊搜索
    apply = ".inp-btn > input:nth-child(1)"

    # 第一條結果
    first_result = (
        "#root > div > div > div > div > div:nth-child(1) > div.item-root a.cover-link"
    )

    # 評分
    rating = (
        "#interest_sectl > div.rating_wrap.clearbox > div.rating_self.clearfix > strong"
    )


async def test_lifetimes(pyppeteer: Browser):
    page = await pyppeteer.new_page()
    await page.goto('https://movie.douban.com/')

    await page.type(Elements.query, "活着")
    await page.click(Elements.apply)

    await page.waitfor(Elements.first_result)
    await page.click(Elements.first_result)

    await page.waitfor(Elements.rating)
    rating = await page.get_value(Elements.rating)
    
    assert float(rating) >= 9.0

執行測試用例,看一下效果:

斷言電影《活着》的豆瓣評分大於 9.0

這裏我們無需指定瀏覽器的路徑,pytest-pyppeteer 會在對應平臺默認的安裝路徑下搜尋 Chrome 的可執行文件。

也可以通過 --executable-path命令行選項顯示的指定 Chrome 的路徑。

或者,在你的conftest.py文件中指定:

@pytest.fixture(scope="session")
def executable_path(executable_path):
    if executable_path is None:
        return "path/to/Chrome/or/Chromium"
    return executable_path

其它支持的命令行選項,包括:

  • --headless:使用瀏覽器的無頭模式;

  • --args:爲瀏覽器指定其它參數。例如:指定代理服務器:

    $ pytest --args proxy-server "localhost:5555,direct://" --args proxy-bypass-list "192.0.0.1/8;10.0.0.1/8"
    
  • --window-size:指定瀏覽器的大小,默認是 800*600;--window-size 0 0表示最大化瀏覽器;

同時操作多個瀏覽器

用下面這個測試用例來說明:斷言書籍《活着》的豆瓣評分高於其電影的評分。

import asyncio
from dataclasses import dataclass

from pytest_pyppeteer.models import Browser, Page


@dataclass(init=False)
class Elements:
    """公共對象庫"""

    query = "#inp-query"
    apply = ".inp-btn > input:nth-child(1)"


@dataclass(init=False)
class BookElements(Elements):
    url = "https://book.douban.com/"

    first_result = '(//*[@class="item-root"]/a)[1]'
    rating = "#interest_sectl > div > div.rating_self.clearfix > strong"


@dataclass(init=False)
class MovieElements(Elements):
    url = "https://movie.douban.com/"

    first_result = (
        "#root > div > div > div > div > div:nth-child(1) > div.item-root a.cover-link"
    )
    rating = (
        "#interest_sectl > div.rating_wrap.clearbox > div.rating_self.clearfix > strong"
    )


async def query_rating(pyppeteer: Browser, name: str, elements: Elements):
    """獲取電影或者書籍的評分。"""

    page: Page = await pyppeteer.new_page()

    await page.goto(elements.url)

    await page.type(elements.query, name)
    await page.click(elements.apply)

    await page.waitfor(elements.first_result)
    await page.click(elements.first_result)

    await page.waitfor(elements.rating)
    rating = await page.get_value(elements.rating)

    return rating


async def test_multiple_pyppeteer(pyppeteer_factory):
    pyppeteer1 = await pyppeteer_factory()
    pyppeteer2 = await pyppeteer_factory()

    movie_rating, book_rating = await asyncio.gather(
        query_rating(pyppeteer1, "活着", MovieElements),
        query_rating(pyppeteer2, "活着", BookElements)
    )

    assert book_rating >= movie_rating

通過pyppeteer_factory 可以獲取多個瀏覽器實例,再利用 python 標準庫asyncio可以很方便的執行異步操作,節省時間。

執行測試用例,看一下效果:

斷言書籍《活着》的豆瓣評分高於其電影的評分

Github 倉庫

更多功能可以訪問:https://github.com/luizyao/pytest-pyppeteer,如果能幫助到你的話,可以給個 star,也歡迎提 issue 和 pr。

pytest 中文文檔(v6.1.1)

之前翻譯過 pytest v5.1.3 的官方文檔並開源,目前計劃更新到 v6.1.1 版本。

項目更多進度可以訪問:https://github.com/luizyao/pytest-chinese-doc/tree/6.1.1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章