playwright结合Pytest为您的 Web 应用程序编写端到端的测试。
安装pytest插件
C:\Users\lifeng01>pip?install?pytest-playwright
Collecting?pytest-playwright
??Using?cached?pytest_playwright-0.2.2-py3-none-any.whl?(9.8?kB)
Requirement?already?satisfied:?pytest?in?d:\python\python37\lib\site-packages?(from?pytest-playwright)?(6.2.5)
Requirement?already?satisfied:?playwright>=1.13?in?d:\python\python37\lib\site-packages?(from?pytest-playwright)?(1.17.0)
Requirement?already?satisfied:?python-slugify?in?d:\python\python37\lib\site-packages?(from?pytest-playwright)?(5.0.2)
Requirement?already?satisfied:?pytest-base-url?in?d:\python\python37\lib\site-packages?(from?pytest-playwright)?(1.4.2)
Requirement?already?satisfied:?typing-extensions?in?d:\python\python37\lib\site-packages?(from?playwright>=1.13->pytest-playwright)?(3.7.4.3)
Requirement?already?satisfied:?pyee>=8.0.1?in?d:\python\python37\lib\site-packages?(from?playwright>=1.13->pytest-playwright)?(8.2.2)
Requirement?already?satisfied:?websockets>=8.1?in?d:\python\python37\lib\site-packages?(from?playwright>=1.13->pytest-playwright)?(9.1)
Requirement?already?satisfied:?greenlet>=1.0.0?in?d:\python\python37\lib\site-packages?(from?playwright>=1.13->pytest-playwright)?(1.0.0)
Requirement?already?satisfied:?atomicwrites>=1.0?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(1.3.0)
Requirement?already?satisfied:?attrs>=19.2.0?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(19.3.0)
Requirement?already?satisfied:?py>=1.8.2?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(1.9.0)
Requirement?already?satisfied:?toml?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(0.10.0)
Requirement?already?satisfied:?colorama?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(0.4.3)
Requirement?already?satisfied:?pluggy<2.0,>=0.12?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(0.13.1)
Requirement?already?satisfied:?packaging?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(20.9)
Requirement?already?satisfied:?importlib-metadata>=0.12?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(1.7.0)
Requirement?already?satisfied:?iniconfig?in?d:\python\python37\lib\site-packages?(from?pytest->pytest-playwright)?(1.0.1)
Requirement?already?satisfied:?requests>=2.9?in?d:\python\python37\lib\site-packages?(from?pytest-base-url->pytest-playwright)?(2.25.0)
Requirement?already?satisfied:?text-unidecode>=1.3?in?d:\python\python37\lib\site-packages?(from?python-slugify->pytest-playwright)?(1.3)
Requirement?already?satisfied:?zipp>=0.5?in?d:\python\python37\lib\site-packages?(from?importlib-metadata>=0.12->pytest->pytest-playwright)?(3.1.0)
Requirement?already?satisfied:?urllib3<1.27,>=1.21.1?in?d:\python\python37\lib\site-packages?(from?requests>=2.9->pytest-base-url->pytest-playwright)?(1.26.2)
Requirement?already?satisfied:?certifi>=2017.4.17?in?d:\python\python37\lib\site-packages?(from?requests>=2.9->pytest-base-url->pytest-playwright)?(2020.4.5.1)
Requirement?already?satisfied:?idna<3,>=2.5?in?d:\python\python37\lib\site-packages?(from?requests>=2.9->pytest-base-url->pytest-playwright)?(2.9)
Requirement?already?satisfied:?chardet<4,>=3.0.2?in?d:\python\python37\lib\site-packages?(from?requests>=2.9->pytest-base-url->pytest-playwright)?(3.0.4)
Requirement?already?satisfied:?pyparsing>=2.0.2?in?d:\python\python37\lib\site-packages?(from?packaging->pytest->pytest-playwright)?(2.4.7)
Installing?collected?packages:?pytest-playwright
Successfully?installed?pytest-playwright-0.2.2
编写测试用例
import?pytest
from?playwright.sync_api?import?Page
def?test_baidu_com(page:?Page):
????page.goto("https://www.baidu.com")
????#?xpath定位输入框,输入文本内容
????page.fill('//*[@id="kw"]',?"秦时明月")
????#?css点位点击“百度一下”按钮
????page.click('#su')
????#?打印title名称
????print(page.title)
if?__name__?==?'__main__':
????pytest.main(["-v",?"test_baidu_example.py"])
名词解释:
test_baidu_com(page: Page): 自动完成配置类型 ( page 是pytest_playwright 插件提供的一个夹函数,page 指定到类型为Page ,Page 是playwright 库提供的一个类,page 指定类型为Page 就可以调用Page 类中的一些列方法 )
命令行输入命令执行:
PS?F:\project_gitee\Test\playwrightProject\cases>?pytest?--browser?chromium?--video?on
==================================================================================?test?session?starts?==================================================================================
platform?win32?--?Python?3.7.7,?pytest-6.2.5,?py-1.9.0,?pluggy-0.13.1
rootdir:?F:\project_gitee\Test\playwrightProject\cases
plugins:?allure-pytest-2.9.43,?anyio-3.3.4,?base-url-1.4.2,?clarity-1.0.1,?cov-2.8.1,?emoji-0.2.0,?forked-1.3.0,?html-3.1.1,?lazy-fixture-0.6.3,?metadata-1.11.0,?pikachu-0.1.0,?playwrigh
t-0.2.2,?rerunfailures-9.1.1,?xdist-2.2.1
collected?1?item?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
test_baidu_example.py?.????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[100%]
===================================================================================?1?passed?in?1.97s?===================================================================================
命令行常用基础命令:
#?运行测试
pytest?
#?开启页面运行
pytest?--headed
#?指定浏览器运行
pytest?--browser?firefox
#?开启页面运行并指定浏览器运行
pytest?--headed?--browser?firefox
#?指定两个浏览器运行,优先运行火狐再运行谷歌
pytest?--browser?firefox?--browser?chromium
#?使用浏览器频道,支持谷歌浏览器(我的电脑其他浏览器是报错的)
pytest?--browser-channel?chromium
#?用慢动作运行测试
pytest?--slowmo?100
#?指定谷歌浏览器,开启记录每次测试的轨迹(生成一个.zip包,存放在test-results文件夹中)
pytest?--browser?chromium?--tracing?on(on:开;off:关)
#?指定谷歌浏览器,开启每次测试录制视频(生成一个.webm包,存放在test-results文件夹中)
pytest?--browser?chromium?--video?on(on:开;off:关)
#?指定谷歌浏览器,开启每次测试后是否自动截屏(生成一个.png图片,存放在test-results文件夹中)
pytest?--browser?chromium?--screenshot?on
import?pytest
from?playwright.sync_api?import?Page
@pytest.mark.skip_browser("firefox")
def?test_baidu_com(page:?Page):
????page.goto("https://www.baidu.com")
????#?xpath定位输入框,输入文本内容
????page.fill('//*[@id="kw"]',?"秦时明月")
????#?css点位点击“百度一下”按钮
????page.click('#su')
????#?打印title名称
????print(page.title)
if?__name__?==?'__main__':
????pytest.main(["-v",?"test_baidu_example.py"])
import?pytest
from?playwright.sync_api?import?Page
@pytest.mark.only_browser("chromium")
def?test_baidu_com(page:?Page):
????page.goto("https://www.baidu.com")
????#?xpath定位输入框,输入文本内容
????page.fill('//*[@id="kw"]',?"秦时明月")
????#?css点位点击“百度一下”按钮
????page.click('#su')
????#?打印title名称
????print(page.title)
if?__name__?==?'__main__':
????pytest.main(["-v",?"test_baidu_example.py"])
忽略 HTTPS 错误和设置自定义视口大小
- 第一种是写在conftest.py中,然后直接运行测试用例:
#?conftest.py
import?pytest
@pytest.fixture(scope="session")
def?browser_context_args(browser_context_args):
????return?{
????????**browser_context_args,
????????"ignore_https_errors":?True,
????}
@pytest.fixture(scope="session")
def?browser_context_args(browser_context_args):
????return?{
????????**browser_context_args,
????????"viewport":?{
????????????"width":?1920,
????????????"height":?1080,
????????}
????}
- 测试用例写法如下(最好这样写,不然运行就报错,作者已采坑):
import?pytest
from?playwright.sync_api?import?Page
def?test_example(page:?Page):
????page.goto("http://www.baidu.com")
????assert?page.title()?==?"百度一下,你就知道"
????page.close()
if?__name__?==?'__main__':
????pytest.main(["-v",?"test_example.py"])
PS?F:\project_gitee\Test\playwrightProject\cases>?pytest?--headed?--browser?chromium
==================================================================================?test?session?starts?==================================================================================
platform?win32?--?Python?3.7.7,?pytest-6.2.5,?py-1.9.0,?pluggy-0.13.1
rootdir:?F:\project_gitee\Test\playwrightProject\cases
plugins:?allure-pytest-2.9.43,?anyio-3.3.4,?asyncio-0.16.0,?base-url-1.4.2,?clarity-1.0.1,?cov-2.8.1,?emoji-0.2.0,?forked-1.3.0,?html-3.1.1,?lazy-fixture-0.6.3,?metadata-1.11.0,?pikachu-
0.1.0,?playwright-0.2.2,?rerunfailures-9.1.1,?xdist-2.2.1
collected?1?item?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
test_example.py?.??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[100%]
===================================================================================?1?passed?in?2.39s?===================================================================================
import?pytest
from?playwright.sync_api?import?sync_playwright
def?test_example():
????with?sync_playwright()?as?p:
????????browser?=?p.chromium.launch(headless=False)
????????page?=?browser.new_context(
????????????ignore_https_errors=True,
????????????viewport={
????????????????"width":?1920,
????????????????"height":?1040,
????????????}
????????)
????????page?=?page.new_page()
????????page.goto("http://www.baidu.com")
????????assert?page.title()?==?"百度一下,你就知道"
????????browser.close()
if?__name__?==?'__main__':
????pytest.main(["-v",?"test_example.py"])
名词解释:
p.chromium.launch(headless=False) :headless=False 是开启有页面运行(默认是True ,也就是无头浏览器)
#?conftest.py
import?pytest
@pytest.fixture(scope="session")
def?browser_context_args(browser_context_args,?playwright):
????iphone_11?=?playwright.devices['iPhone?11?Pro']
????return?{
????????**browser_context_args,
????????**iphone_11,
????}
- 测试用例写法如下(最好这样写,不然运行就报错,作者已采坑):
import?pytest
from?playwright.sync_api?import?Page
def?test_example(page:?Page):
????page.goto("http://www.baidu.com")
????assert?page.title()?==?"百度一下,你就知道"
????page.close()
if?__name__?==?'__main__':
????pytest.main(["-v",?"test_example.py"])
PS?F:\project_gitee\Test\playwrightProject\cases>?pytest?--headed?--browser?chromium
==================================================================================?test?session?starts?==================================================================================
platform?win32?--?Python?3.7.7,?pytest-6.2.5,?py-1.9.0,?pluggy-0.13.1
rootdir:?F:\project_gitee\Test\playwrightProject\cases
plugins:?allure-pytest-2.9.43,?anyio-3.3.4,?asyncio-0.16.0,?base-url-1.4.2,?clarity-1.0.1,?cov-2.8.1,?emoji-0.2.0,?forked-1.3.0,?html-3.1.1,?lazy-fixture-0.6.3,?metadata-1.11.0,?pikachu-
0.1.0,?playwright-0.2.2,?rerunfailures-9.1.1,?xdist-2.2.1
collected?1?item?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
test_example.py?F??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[100%]
=======================================================================================?FAILURES?========================================================================================
________________________________________________________________________________?test_example[chromium]?_________________________________________________________________________________
page?=?<Page?url='https://m.baidu.com/?from=844b&vit=fps'>
????def?test_example(page:?Page):
????????page.goto("http://www.baidu.com")
>???????assert?page.title()?==?"百度一下,你就知道"
E???????AssertionError:?assert?'百度一下'?==?'百度一下,你就知道'
E?????????-?百度一下,你就知道
E?????????+?百度一下
test_example.py:15:?AssertionError
================================================================================?short?test?summary?info?================================================================================
FAILED?test_example.py::test_example[chromium]?-?AssertionError:?assert?'百度一下'?==?'百度一下,你就知道'
===================================================================================?1?failed?in?3.14s?===================================================================================
这里运行后,打开的web 页面,是一个手机形状的页面,仿的是手机浏览器(代码中指定的是iPhone 11 Pro )
持久上下文
它的意思就是打开一个web 页面,会在这个web 页面开多个新标签页面去执行测试用例。
例如:我有两个测试用例需要执行,如果使用持久上下文,就会打开一个web 页面,然后web 页面的第一个标签页运行第一个测试用例,第二个标签页运行第二个测试用例,直到把所有测试用例运行完了,关闭整个web 页面,结束。
当然,如果你没有使用持久上下文,那就是打开web 页面执行第一个测试用例,执行完第一个测试用例关闭web 页面,然后再打开web 页面执行第二个测试用例,执行完第二个测试用例关闭web 页面,结束。
import?pytest
from?playwright.sync_api?import?BrowserType
from?typing?import?Dict
@pytest.fixture(scope="session")
def?context(
????browser_type:?BrowserType,
????browser_type_launch_args:?Dict,
????browser_context_args:?Dict
):
????context?=?browser_type.launch_persistent_context("./data",?**{
????????**browser_type_launch_args,
????????**browser_context_args,
????????"locale":?"de-DE",
????})
????yield?context
????context.close()
名词解释:
./data 用户数据目录的路径,它存储浏览器会话数据,如cookie和本地存储。browser_type_launch_args 如果没有设置值,返回的就是一个空字典;它里面的参数就是和p.chromium.launch() 中的传参一致的,此处了解下,后面具体介绍。browser_context_args 如果没有设置值,返回的就是一个空字典;它里面的参数就和context = browser.new_context() 中的传参一致的,此处了解下,后面具体介绍。locale 指定用户区域设置,例如' en-GB '、' de-DE '等。
命令行运行测试用例:
PS?F:\project_gitee\Test\playwrightProject\cases>?pytest?--headed?--browser?chromium
==================================================================================?test?session?starts?==================================================================================
platform?win32?--?Python?3.7.7,?pytest-6.2.5,?py-1.9.0,?pluggy-0.13.1
rootdir:?F:\project_gitee\Test\playwrightProject\cases
plugins:?allure-pytest-2.9.43,?anyio-3.3.4,?asyncio-0.16.0,?base-url-1.4.2,?clarity-1.0.1,?cov-2.8.1,?emoji-0.2.0,?forked-1.3.0,?html-3.1.1,?lazy-fixture-0.6.3,?metadata-1.11.0,?pikachu-
0.1.0,?playwright-0.2.2,?rerunfailures-9.1.1,?xdist-2.2.1
collected?2?items????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
test_baidu_example.py?.????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[?50%]
test_example.py?.??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[100%]
===================================================================================?2?passed?in?3.12s?===================================================================================
必须知晓问题:
- 上述文章中的
browser_type_launch_args 和browser_context_args 都是pytest_playwright 插件提供的测试夹会话: - 展示
pytest_playwright 插件部分源码:
@pytest.fixture(scope="session")
def?browser_type_launch_args(pytestconfig:?Any)?->?Dict:
????launch_options?=?{}
????headed_option?=?pytestconfig.getoption("--headed")
????if?headed_option:
????????launch_options["headless"]?=?False
????browser_channel_option?=?pytestconfig.getoption("--browser-channel")
????if?browser_channel_option:
????????launch_options["channel"]?=?browser_channel_option
????slowmo_option?=?pytestconfig.getoption("--slowmo")
????if?slowmo_option:
????????launch_options["slow_mo"]?=?slowmo_option
????return?launch_options
@pytest.fixture(scope="session")
def?browser_context_args(
????pytestconfig:?Any,
????playwright:?Playwright,
????device:?Optional[str],
)?->?Dict:
????context_args?=?{}
????if?device:
????????context_args.update(playwright.devices[device])
????base_url?=?pytestconfig.getoption("--base-url")
????if?base_url:
????????context_args["base_url"]?=?base_url
????video_option?=?pytestconfig.getoption("--video")
????capture_video?=?video_option?in?["on",?"retain-on-failure"]
????if?capture_video:
????????context_args["record_video_dir"]?=?artifacts_folder.name
????return?context_args
以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,直接私信留言会及时修正发布;非常期待你的点赞和分享哟,谢谢!
未完,待续…
一直都在努力,希望您也是!
微信搜索公众号:就用python
文章作者:李 锋|编辑排版:梁莉莉
|