pytest插件,允许您使用测试指标报告自动化操作和断言,执行纯YAML文件
项目描述
pytest-play
pytest-play 是一款无需编写代码、通用、可插拔和可扩展的 自动化工具,不仅限于 测试自动化,基于出色的 pytest 测试框架,允许您通过操作和断言定义和执行包含脚本或测试场景的 YAML 文件,即使是非技术用户也可以实现和管理
自动化(不一定是测试自动化)。您可以在单个文件上构建一组操作(例如,调用基于 JSON 的 API 端点,在条件匹配时执行操作)或具有许多测试场景的测试自动化项目。
例如,您可以创建始终是最新测试数据,支持手动测试活动,构建实时模拟器等。
无需编写代码,或者更准确地说,几乎无需编写代码。如果您必须编写针对操作结果的断言或某些条件表达式,您只需要具备基本的 Python 或 JavaScript 表达式知识,学习曲线平缓(类似于 variables['foo'] == 'bar')
通用。它不是另一个仅适用于浏览器自动化、API 等的自动化工具。您可以使用相同的工具驱动浏览器、执行一些 API 调用、执行数据库查询,以及使用断言进行不同的技术
因此,有多个免费或付费的测试框架或自动化工具,很多时候它们仅针对单一测试需求领域,并且不可扩展:仅 API 测试、仅 UI 测试等。如果您正在测试仅涉及 CMS 的 Web 应用程序,这可能是可以的,但如果您正在处理反应性物联网应用程序,您可能需要更多,进行跨操作或针对不同系统的跨检查,或者在 pytest-play 上构建更复杂的东西
功能强大。它不是另一个测试自动化工具,它仅扩展了 pytest 框架并引入了另一种范式,并继承了众多优点(测试数据与测试实现解耦,让您可以一次编写并多次执行相同的场景,得益于原生的参数化支持、报告、与测试管理工具集成、许多有用的命令行选项、浏览器和远程 Selenium 集群集成等)
可插拔和可扩展。假设您需要与一个尚未由 pytest-play 插件支持的系统进行交互,您可以自己编写或付费请他人编写。此外,还有一个脚手架工具,让您可以实施自己的命令:[https://github.com/davidemoro/cookiecutter-play-plugin](https://github.com/davidemoro/cookiecutter-play-plugin)
易于使用。为什么是 YAML?易于阅读、易于编写、简单的语法、易于验证,没有括号地狱。尽管目前没有用于浏览器交互或 API 调用的录制工具,但基于非常常见模式的文档让您可以无痛苦地逐个复制、粘贴和编辑命令
免费软件。它是一个基于庞大且友好的 pytest 社区的开源项目
易于安装。唯一的先决条件是 Docker,多亏了 davidemoro/pytest-play Docker Hub 容器。或者更好,使用 docker,无需安装:您只需在项目文件夹中输入以下命令 docker run -i --rm -v $(pwd):/src davidemoro/pytest-play。请参阅 [https://hub.docker.com/r/davidemoro/pytest-play](https://hub.docker.com/r/davidemoro/pytest-play)
请查看页面底部扩展 pytest-play 的第三方插件
如何工作
根据您的需求和技能,您可以选择使用 pytest-play 编程编写一些 Python 代码或采用无 Python 的方法。
如前所述,使用pytest-play,您可以创建无需或仅需很少Python知识的无代码脚本或测试场景:一个文件 test_XXX.yml(例如,test_something.yml,其中 test_ 和 .yml 很重要)将被自动识别和执行,无需触碰任何 *.py 模块。
您可以使用 pytest test_XXX.yml 运行单个场景,或通过名称或关键字标记过滤整个套件。
尽管 pytest-play 从一开始就支持JSON格式,但 pytest-play>=2.0 版本将仅支持YAML以提高可用性。
无Python(纯YAML)
在这里,您可以查看一个 pytest-play 项目的内容,其中不包含任何包含登录场景的Python文件
$ tree . ├── env-ALPHA.yml (OPTIONAL) └── test_login.yml
并且您可能有一些全局变量在特定目标环境的设置文件中
$ cat env-ALPHA.yml pytest-play: base_url: https://www.yoursite.com
测试场景包含操作、断言和可选元数据(需要 play_selenium 外部插件)
$ cat test_login.yml --- markers: - login test_data: - username: siteadmin password: siteadmin - username: editor password: editor - username: reader password: reader --- - comment: visit base url type: get provider: selenium url: "$base_url" - comment: click on login link locator: type: id value: personaltools-login type: clickElement provider: selenium - comment: provide a username locator: type: id value: __ac_name text: "$username" type: setElementText provider: selenium - comment: provide a password locator: type: id value: __ac_password text: "$password" type: setElementText provider: selenium - comment: click on login submit button locator: type: css value: ".pattern-modal-buttons > input[name=submit]" type: clickElement provider: selenium - comment: wait for page loaded locator: type: css value: ".icon-user" type: waitForElementVisible provider: selenium
第一个可选的YAML文档包含一些元数据,这些元数据被称为 markers,因此您可以通过使用标记表达式调用pytest来过滤要执行的测试,解耦测试数据等。
相同的 test_login.yml 场景将使用不同的解耦测试数据 test_data 执行3次,这些测试数据定义在其第一个可选的YAML文档内部(两个 --- 线之间的块)。
所以只需编写一次,就可以用不同的测试数据多次执行!
您在这里可以看到一个hello world示例
如前所述,元数据文档是可选的,因此您的YAML文件中可能有1个或2个文档。您可以在元数据格式中找到更多信息。
在这里,您可以看到没有元数据部分的相同示例,为了完整性起见
--- - comment: visit base url type: get provider: selenium url: "http://YOURSITE" - comment: click on login link type: clickElement provider: selenium locator: type: id value: personaltools-login - comment: provide a username type: setElementText provider: selenium locator: type: id value: __ac_name text: "YOURUSERNAME" - comment: provide a password type: setElementText provider: selenium locator: type: id value: __ac_password text: "YOURPASSWORD" - comment: click on login submit button type: clickElement provider: selenium locator: type: css value: ".pattern-modal-buttons > input[name=submit]" - comment: wait for page loaded type: waitForElementVisible provider: selenium locator: type: css value: ".icon-user"
程序化
您也可以通过程序调用pytest-play。
您可以定义一个测试 test_login.py 如此
def test_login(play): data = play.get_file_contents( 'my', 'path', 'etc', 'login.yml') play.execute_raw(data, extra_variables={})
或者,如果您正在使用 pytest-bdd 实现基于BDD的测试,则可能使用此程序化方法。
核心命令
pytest-play 提供了一些核心命令,允许您
编写简单的Python断言、表达式和变量
重用步骤,包括其他测试场景脚本
为特定提供者提供默认命令模板(例如,默认情况下为所有请求添加HTTP身份验证头)
提供通用的等待机制。在执行依赖于前一步骤完成的后续命令之前,非常有用,等待可观察的异步事件完成其流程
您可以根据 RestrictedPython 包编写受限制的Python表达式和断言。
RestrictedPython 是一个工具,有助于定义Python语言的一个子集,该子集允许将程序输入提供给受信任的环境。RestrictedPython不是一个沙箱系统或安全环境,但它有助于定义受信任的环境并在其中执行不受信任的代码。
参见
如何重用步骤
您可以使用 include 命令分割您的命令并重用它们,以避免重复
- provider: include type: include path: "/some-path/included-scenario.yml"
您可以创建一个变量,用于存储您的测试脚本所在的基础文件夹。
默认命令
一些命令需要很多详尽的选项,您不想重复(例如,对于 play_requests 的身份验证头)。
您无需复制所有头部信息,可以使用一个以提供者名称为键,默认命令为值的 pytest-play 来初始化(此示例需要外部插件 play_selenium)
- provider: python type: store_variable name: bearer expression: "'BEARER'" - provider: python type: store_variable name: play_requests expression: "{'parameters': {'headers': {'Authorization': '$bearer'}}}" - provider: play_requests type: GET comment: this is an authenticated request! url: "$base_url"
存储变量
您可以将 pytest-play 变量存储
- provider: python type: store_variable expression: "1+1" name: foo
编写 Python 断言
您可以根据 Python 表达式编写断言
- provider: python type: assert expression: variables['foo'] == 2
睡眠
睡眠指定秒数
- provider: python type: sleep seconds: 2
执行 Python 表达式
您可以执行一个 Python 表达式
- provider: python type: exec expression: "1+1"
条件语句和循环
如果您需要循环一系列命令或等待某物,可以使用 while 命令。当条件表达式为真时,它会执行子命令序列。假设您有一个包含整数的 countdown 变量 10,则命令块将被执行 10 次
--- - provider: python type: while expression: variables['countdown'] >= 0 timeout: 2.3 poll: 0.1 sub_commands: - provider: python type: store_variable name: countdown expression: variables['countdown'] - 1
while 命令取代了其他旧命令 wait_until(当条件为真时停止)或 wait_until_not 命令。
条件命令(Python)
您可以根据以下基于 Python 的跳过条件跳过任何命令
- provider: include type: include path: "/some-path/assertions.yml" skip_condition: variables['cassandra_assertions'] is True
如何断言命令的执行时间
引擎为每个执行的命令更新一个名为 pytest-play 的变量 _elapsed。因此,您可以编写一些代码来
--- - type: GET provider: play_requests url: https://api.chucknorris.io/jokes/categories expression: "'dev' in response.json()" - type: assert provider: python expression: "variables['_elapsed'] > 0"
生成 JUnit XML 报告
使用 --junit-xml 命令行选项,例如
--junit-xml results.xml
您将获得每个测试用例的错误、在 system-output 中执行的命令(不要使用 -s 或 --capture=no,否则您将看不到 system-output 中的命令)和执行时间指标(全局、每个测试用例和每个单个命令,多亏了 _elapsed 属性,它在每个执行的命令中跟踪,并在 system-output 中显示)。
在这里,您可以看到一个标准的 results.xml 文件
<?xml version="1.0" encoding="utf-8"?><testsuite errors="0" failures="0" name="pytest" skipped="0" tests="1" time="0.360"><testcase classname="test_assertion.yml" file="test_assertion.yml" name="test_assertion.yml" time="0.326"><system-out>{'expression': '1 == 1', 'provider': 'python', 'type': 'assert', '_elapsed': 0.0003077983856201172} {'expression': '0 == 0', 'provider': 'python', 'type': 'assert', '_elapsed': 0.0002529621124267578} </system-out></testcase></testsuite>
生成具有自定义属性和执行时间指标的定制 JUnit XML 报告
您可以通过机器可解析的格式跟踪执行时间指标,以便进行监控和测量您认为重要的事情。例如,您可以跟踪使用
响应时间(例如,返回 POST json 有效载荷需要多少时间)
API 调用与响应式 Web 应用程序更新或某些异步数据出现在事件存储器之间发生的时间
浏览器用户输入与结果更新之间发生的时间(例如,实时搜索)
登录按钮与页面加载并可使用之间发生的时间(例如,在浏览器操作后点击目标按钮需要多少时间)
在 JUnit XML 报告中跟踪响应时间指标
例如,使用命令行选项 --junit-xml report.xml 执行的 test_categories.yml 文件(需要 play_requests 插件)
test_data: - category: dev - category: movie - category: food --- - type: GET provider: play_requests url: https://api.chucknorris.io/jokes/categories expression: "'$category' in response.json()" - provider: metrics type: record_elapsed name: categories_time - type: assert provider: python expression: "variables['categories_time'] < 2.5" comment: you can make an assertion against the categories_time
将生成一个扩展的 report.xml 文件,具有如下自定义属性
<?xml version="1.0" encoding="utf-8"?><testsuite errors="0" failures="0" name="pytest" skipped="0" tests="3" time="2.031"><testcase classname="test_categories.yml" file="test_categories.yml" name="test_categories.yml0" time="0.968"><properties><property name="categories_time" value="0.5829994678497314"/></properties><system-out>{'expression': "'dev' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.5829994678497314} {'name': 'categories_time', 'provider': 'metrics', 'type': 'record_elapsed', '_elapsed': 3.3855438232421875e-05} {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2.5", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0006382465362548828} </system-out></testcase><testcase classname="test_categories.yml" file="test_categories.yml" name="test_categories.yml1" time="0.481"><properties><property name="categories_time" value="0.4184422492980957"/></properties><system-out>{'expression': "'movie' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.4184422492980957} {'name': 'categories_time', 'provider': 'metrics', 'type': 'record_elapsed', '_elapsed': 2.09808349609375e-05} {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2.5", 'provider': 'python', 'type': 'assert', '_elapsed': 0.000553131103515625} </system-out></testcase><testcase classname="test_categories.yml" file="test_categories.yml" name="test_categories.yml2" time="0.534"><properties><property name="categories_time" value="0.463592529296875"/></properties><system-out>{'expression': "'food' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.463592529296875} {'name': 'categories_time', 'provider': 'metrics', 'type': 'record_elapsed', '_elapsed': 2.09808349609375e-05} {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2.5", 'provider': 'python', 'type': 'assert', '_elapsed': 0.00054931640625} </system-out></testcase></testsuite>
并且自定义属性 categories_time 将跟踪每个测试用例执行,例如
<properties> <property name="categories_time" value="0.5829994678497314"/> </properties>
JUnit XML 报告中的高级指标
在本示例中,我们希望测量页面变为可交互(页面响应用户交互)所需的时间,并评估实时搜索功能的更新时间。让我们看看 test_search.yml 的示例(需要 play_selenium)。
--- - provider: selenium type: get url: https://www.plone-demo.info/ - provider: metrics type: record_elapsed_start name: load_time - provider: selenium type: setElementText text: plone 5 locator: type: id value: searchGadget - provider: metrics type: record_elapsed_stop name: load_time - provider: metrics type: record_elapsed_start name: live_search_time - provider: selenium type: waitForElementVisible locator: type: css value: li[data-url$="https://www.plone-demo.info/front-page"] - provider: metrics type: record_elapsed_stop name: live_search_time
如果您使用 --junit-xml results.xml 选项执行此场景,您将获得类似于以下结果的 results.xml 文件。
<?xml version="1.0" encoding="utf-8"?><testsuite errors="0" failures="0" name="pytest" skipped="0" tests="1" time="13.650"><testcase classname="test_search.yml" file="test_search.yml" name="test_search.yml" time="13.580"><properties><property name="load_time" value="1.1175920963287354"/><property name="live_search_time" value="1.0871295928955078"/></properties><system-out>{'provider': 'selenium', 'type': 'get', 'url': 'https://www.plone-demo.info/', '_elapsed': 9.593282461166382} {'name': 'load_time', 'provider': 'metrics', 'type': 'record_elapsed_start', '_elapsed': 1.1682510375976562e-05} {'locator': {'type': 'id', 'value': 'searchGadget'}, 'provider': 'selenium', 'text': 'plone 5', 'type': 'setElementText', '_elapsed': 1.1019845008850098} {'name': 'load_time', 'provider': 'metrics', 'type': 'record_elapsed_stop', '_elapsed': 1.9788742065429688e-05} {'name': 'live_search_time', 'provider': 'metrics', 'type': 'record_elapsed_start', '_elapsed': 1.0013580322265625e-05} {'locator': {'type': 'css', 'value': 'li[data-url$="https://www.plone-demo.info/front-page"]'}, 'provider': 'selenium', 'type': 'waitForElementVisible', '_elapsed': 1.060795545578003} {'name': 'live_search_time', 'provider': 'metrics', 'type': 'record_elapsed_stop', '_elapsed': 2.3603439331054688e-05} </system-out></testcase></testsuite>
在这种情况下,您会发现关键指标 load_time 为 1.11 秒,而 live_search_time 为 1.09 秒,如下所示。
<properties> <property name="load_time" value="1.1175920963287354"/> <property name="live_search_time" value="1.0871295928955078"/> </properties>
因此,借助 JUnit XML 报告,您可以使用机器可读格式跟踪响应时间(不仅限于基于浏览器的计时),以便在无法直接在测试系统上跟踪计时的情况下,以可接受的近似值由第三方系统摄取。
使用表达式跟踪 JUnit XML 报告中的任何属性
让我们看看 test_categories.yml(需要 play_selenium)。
test_data: - category: dev - category: movie - category: food --- - type: GET provider: play_requests url: https://api.chucknorris.io/jokes/categories expression: "'$category' in response.json()" - provider: metrics type: record_property name: categories_time expression: "variables['_elapsed']*1000" - type: assert provider: python expression: "variables['categories_time'] < 2500" comment: you can make an assertion against the categories_time
使用 --junit-xml results.xml 命令行选项生成一些自定义属性(以毫秒为单位的 categories_time 使用 Python 表达式)。
<?xml version="1.0" encoding="utf-8"?><testsuite errors="0" failures="0" name="pytest" skipped="0" tests="3" time="2.312"><testcase classname="test_categories.yml" file="test_categories.yml" name="test_categories.yml0" time="1.034"><properties><property name="categories_time" value="610.3124618530273"/></properties><system-out>{'expression': "'dev' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.6103124618530273} {'expression': "variables['_elapsed']*1000", 'provider': 'python', 'type': 'exec', '_elapsed': 0.0006859302520751953} {'expression': "variables['_elapsed']*1000", 'name': 'categories_time', 'provider': 'metrics', 'type': 'record_property', '_elapsed': 0.006484270095825195} {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2500", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0005526542663574219} </system-out></testcase><testcase classname="test_categories.yml" file="test_categories.yml" name="test_categories.yml1" time="0.550"><properties><property name="categories_time" value="443.72105598449707"/></properties><system-out>{'expression': "'movie' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.44372105598449707} {'expression': "variables['_elapsed']*1000", 'provider': 'python', 'type': 'exec', '_elapsed': 0.0009415149688720703} {'expression': "variables['_elapsed']*1000", 'name': 'categories_time', 'provider': 'metrics', 'type': 'record_property', '_elapsed': 0.01613616943359375} {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2500", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0011241436004638672} </system-out></testcase><testcase classname="test_categories.yml" file="test_categories.yml" name="test_categories.yml2" time="0.676"><properties><property name="categories_time" value="576.5485763549805"/></properties><system-out>{'expression': "'food' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.5765485763549805} {'expression': "variables['_elapsed']*1000", 'provider': 'python', 'type': 'exec', '_elapsed': 0.0006375312805175781} {'expression': "variables['_elapsed']*1000", 'name': 'categories_time', 'provider': 'metrics', 'type': 'record_property', '_elapsed': 0.006584644317626953} {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2500", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0005452632904052734} </system-out></testcase></testsuite>
获取每次执行要跟踪的指标,例如
<properties><property name="categories_time" value="610.3124618530273"/></properties>
因此,您可以跟踪每个测试执行的类别,或您想要的任何内容。
使用 statsd/graphite 监控测试指标
如果您喜欢测量一切的方法,您可以在正常测试执行或高负载/压力测试期间,从最终用户的角度跟踪和监控有趣的定制测试指标,这要归功于 statsd/graphite 集成。
衡量重要关键指标的原因有很多
使用过去跟踪的同一指标的统计信息,在相同条件下比较不同版本的性能(不再仅仅是说系统今天 似乎更慢)
预测前端许多项目下的系统行为(例如,评估浏览器处理由无限滚动插件管理的成千上万的项目)
预测系统在高负载下的行为
您可以使用 Docker 在几分钟内安装 statsd/graphite。
基本上,您可以在 statsd/graphite 上跟踪每个 数值 指标,就像我们将要看到的那样,使用用于跟踪 JUnit XML 报告中指标的相同命令。
此外,但不是必需的,安装名为 pytest-statsd 的第三方插件。您可以在 statsd/graphite 上跟踪
执行时间
每个状态的执行测试数量(通过,失败,错误等)
先决条件(您需要安装默认未安装的可选 statsd 客户端):
pip install pytest-play[statsd]
用法(与 pytest-statsd 兼容的 CLI 选项)
--stats-d [--stats-prefix play --stats-host http://myserver.com --stats-port 3000]
其中
--stats-d,启用 statsd
--stats-prefix(可选),如果您计划将多个项目的结果发送到同一服务器。例如,如果您提供 play 作为前缀,您将获得一个时间指标,其键为 stats.timers.play.YOURMETRIC.mean(或您可以使用 .mean,.upper,upper_90 等))
--stats-host,默认为 localhost
默认情况下,--stats-port 为 8125
现在您可以使用之前看到的 record_elapsed 或 record_elapsed_start/record_elapsed_stop 命令来跟踪时间指标(pytest-play 会为您发送所需转换为毫秒的时间值到 statsd)。
如果您想使用 record_property 命令跟踪自定义指标,您必须提供一个名为 metric_type 的附加参数。例如:
- provider: metrics type: record_property name: categories_time expression: "variables['_elapsed']*1000" metric_type: timing - provider: metrics type: record_property name: fridge_temperature expression: "4" metric_type: gauge
关于 record_property 命令的一些附加信息
如果您在 record_property 命令中没有提供 metric_type 选项,则值将不会发送到 statsd(如果提供了 --junit-xml 选项,最终它们将在 JUnit XML 报告中跟踪)。
如果您提供了一个允许的 metric_type 值(timing 或 gauge),则非数字值将被视为错误(将引发 ValueError 异常)。
不允许的 metric_type 值将被视为错误。
如果您提供 timing 作为 metric_type,则您需要提供一个以毫秒为单位的数字值。
监控 HTTP 响应时间
监控 API 响应时间(见 https://github.com/pytest-dev/pytest-play/tree/features/examples/statsd_graphite_monitoring)
浏览器指标
使用 Selenium 从最终用户的角度监控浏览器指标(见 https://github.com/pytest-dev/pytest-play/tree/features/examples/statsd_graphite_monitoring_selenium)
从页面加载到页面可用
实时搜索响应性
以编程方式记录指标
如果您不想使用 pytest-play 但需要记录测试指标,您可以将 pytest-play 作为库使用:
def test_programmatically(play): play.execute_command({ 'provider': 'metrics', 'type': 'record_property', 'name': 'oil_temperature', 'expression': '60', 'metric_type': 'gauge'})
使用 pytest-play 和 bzt/Taurus(BlazeMeter)进行性能测试
您可以将所有 pytest-play 场景重用,并使用 bzt/Taurus(与 BlazeMeter 兼容,并具有所有其优点)将其转换为性能测试。
添加一个不带 test_ 前缀的 bzt/Taurus YAML 文件(完整示例在此处 bzt_performance)
settings: artifacts-dir: /tmp/%Y-%m-%d_%H-%M-%S.%f execution: - executor: pytest scenario: pytest-run iterations: 1 scenarios: pytest-run: # additional-args: --stats-d --stats-prefix play script: scripts/ services: - module: shellexec prepare: - pip3 install -r https://raw.githubusercontent.com/davidemoro/pytest-play-docker/master/requirements.txt
然后运行以下命令
docker run --rm -it -v $(pwd):/src --user root --entrypoint "bzt" davidemoro/pytest-play bzt.yml
您将看到 bzt 正在运行,正在播放我们的场景
您可以通过取消注释 additional-args 来传递其他 pytest 命令行选项(例如,启用 statsd 以监控关键用户指标或任何其他 cli 选项)。
bzt/Taurus 的更多信息请在这里
在有效负载中动态表达式而不声明变量
如果您必须向 REST 终端或包含动态值的 MQTT 消息发送某个有效负载,您可以使用 store_variable 存储一个变量,并在需要时在有效负载中使用 $variable_name。存储变量很酷,如果您稍后会重用该值,但是如果您只需要生成一个动态值,例如毫秒级的时间戳,您可以使用 {! EXPRESSION !} 格式。
例如(《a href="https://github.com/davidemoro/play_mqtt" rel="nofollow">play_mqtt 插件需要)
--- - comment: python expressions in mqtt payload (without declaring variables) provider: mqtt type: publish host: "$mqtt_host" port: "$mqtt_port" endpoint: "$mqtt_endpoint/$device_serial_number" payload: '{ "measure_id": [124], "obj_id_L": [0], "measureType": ["float"], "start_time": {! int(datetime.datetime.utcnow().timestamp()*1000) !}, "bin_value": [1] }'
其中,表达式
{! int(datetime.datetime.utcnow().timestamp()*1000) !},
将被打印
1553007973702
基于浏览器的命令
pytest-play 核心不再包含基于浏览器的命令。已移动到 play_selenium 外部插件。
pytest-play 是可插拔和可扩展的。
pytest-play 拥有可插拔的架构,您可以扩展它。
例如,您可能希望支持自己的命令,支持非 UI 命令,如执行原始 POST/GET 等调用,模拟物联网设备活动,提供与复杂 UI 小部件(如日历小部件)的简单交互,通过实现二进制协议的串行端口向设备发送命令等。
如何注册新的命令提供者
假设您想使用以下命令扩展 pytest-play
command = {'type': 'print', 'provider': 'newprovider', 'message': 'Hello, World!'}
您只需实现一个命令提供者
from pytest_play.providers import BaseProvider class NewProvider(BaseProvider): def this_is_not_a_command(self): """ Commands should be command_ prefixed """ def command_print(self, command): print(command['message']) def command_yetAnotherCommand(self, command): print(command)
并在您的 setup.py 中注册新提供者,添加一个入口点
entry_points={ 'playcommands': [ 'print = your_package.providers:NewProvider', ], },
您也可以为非 UI 命令定义新的提供者。例如,发布 MQTT 消息以模拟物联网设备活动进行集成测试。
如果您愿意,可以使用以下工具生成新的命令提供者
元数据格式
您还可以添加一些场景元数据,在 test_XXX.yml 上方放置另一个 YAML 文档,格式如下
--- markers: - marker1 - marker2 test_data: - username: foo - username: bar --- # omitted scenario steps in this example...
选项详情
markers,您可以使用标记装饰您的场景,并使用标记表达式(如 -m "marker1 and not slow")在 pytest 命令行中过滤要执行的场景
test_data,启用解耦测试数据的参数化,并允许您执行相同的场景多次。例如,上面的示例将执行两次(一次使用“foo”用户名,另一次使用“bar”)
将在下一个功能中添加新选项(例如,跳过场景,xfail,xpass 等)。
示例
文章和演讲
文章
演讲
第三方 pytest-play 插件
play_selenium,pytest-play 插件,在底层使用 Selenium/Splinter 驱动浏览器。Selenium grid 兼容,并具有隐式自动等待操作,以实现更健壮的场景和更少的控制。
play_requests,pytest-play 插件,驱动著名的 Python requests 库进行 HTTP 调用。
play_sql,pytest-play 对 SQL 表达式和断言的支持
play_cassandra,pytest-play 对 Cassandra 表达式和断言的支持
play_dynamodb,pytest-play 对 AWS DynamoDB 查询和断言的支持
play_websocket,pytest-play 对 WebSocket 的支持
play_mqtt,用于支持MQTT的pytest-play插件。感谢play_mqtt,您可以使用它测试一个模拟的IoT设备(该设备通过MQTT发送命令)与具有UI检查的响应式Web应用程序之间的集成。
您还可以构建一个生成消息的模拟器。
请随时通过pull request添加您自己的公共插件!
pytest-play的推文在这里
更新日志
2.3.1 (2019-06-12)
错误修复
修复与pytest 4.6的兼容性。参考#86
文档
更新媒体部分(文章和演讲)
2.3.0 (2019-04-05)
功能和改进
wait_until和wait_until_not现在可以接受没有sub_commands属性的命令
在Python提供者中实现新的while命令(while表达式为真时)
2.2.2 (2019-03-29)
小改动
在引擎上移除内部属性参数
错误修复
添加对pytest-repeat的--count命令行选项的兼容性
文档
说明如何使用{! expr !}表达式生成动态值(例如,在REST或MQTT中不需要存储变量时动态负载)
2.2.1 (2019-03-19)
小改动
添加Python表达式中的内置类型int和float
使Python表达式更具灵活性,以供未来改进(内部更改,不会影响兼容性)
错误修复
修复--setup-plan调用
文档
添加更多示例(bzt/Taurus和pytest-play的性能测试)
2.2.0 (2019-03-01)
statsd集成(可选要求)用于使用statsd/graphite的高级测试指标。如果您使用pytest-play[statsd]安装pytest play以启用可选的statsd支持,您将获得额外的依赖项statsd客户端,并且可以使用由pytest-statsd插件定义的相同cli选项(例如,--stats-d [--stats-prefix myproject --stats-host http://myserver.com --stats-port 3000])。
请注意:尽管上述cli选项与pytest-statsd插件定义的相同,但在撰写本文时,pytest-statsd不是pytest-play的依赖项,因此您不会获得失败次数、通过次数等的统计信息,而只有pytest-play跟踪的统计信息。如果您需要它们,您可以安装pytest-statsd(它与pytest-play兼容)
2.1.0 (2019-02-22)
功能
支持使用system-out元素生成JUnit xml生成文件,用于每个测试用例执行(pytest --junit-xml选项)。默认情况下,除非您使用--capture=no或其别名-s,否则system-out将在JUnit报告中跟踪。
如果启用system-out,则在--junit-xml报告中跟踪每个执行命令的_elapsed时间
在--junit-xml报告中跟踪pytest自定义属性,用于监控和衡量您关心的内容。例如,您可以使用机器可解析的格式跟踪作为关键指标的时间,例如在上一操作结束和下一操作完成之间发生的时间。基本上,您可以在property_name load_login键下跟踪在点击提交按钮和当前命令结束之间发生的时间(例如,点击菜单或可接收文本的文本输入),使用机器可解析的格式。
属性名 property_name 的值耗时将作为标准 pytest-play 变量可用,以便您可以进行额外的断言
每次命令执行后,都会添加/更新一个 pytest-play 变量,报告耗时(可通过 variables['_elapsed'] 访问)。
因此请注意,_elapsed 变量名应被视为一个特殊变量,因此您不应使用此名称来存储变量
在断言失败或命令错误的情况下改进调试。记录变量转储在标准日志和 system-out 中(如果可用)
在断言错误的情况下改进调试性(记录失败的表达式)
添加了一个新的 metrics 提供程序,允许您与 --junit-xml 选项结合跟踪自定义指标。您可以用机器可读的格式跟踪响应时间、动态自定义表达式、不同命令之间发生的时间(例如,测量登录后与页面交互所需的时间、异步更新之前的时间等)。在 metrics 提供程序下,您会发现 record_property、record_elapsed、record_elapsed_start 和 record_elapsed_stop 命令
文档
较小的文档更改
添加更多示例
2.0.2 (2019-02-06)
文档
更多示例
修复 README 中的文档错误(基于 selenium 的示例缺少 provider: selenium)
2.0.1 (2019-01-30)
文档
在 README 中提及 davidemoro/pytest-play docker 容器。现在您可以使用以下 docker 命令使用 pytest-play: docker run -i --rm -v $(pwd):/src davidemoro/pytest-play
错误修复
修复由于 pytest-play 依赖项约束不存在而导致的 pipenv 锁定错误(RestrictedPython>=4.0.b2 -> RestrictedPython>=4.0b2)
2.0.0 (2019-01-25)
重大更改
将 fixture 重命名为 play_json 为 play (#5)
删除 json 支持,仅采用 yaml 格式进行场景 (#5)
删除 .ini 文件用于元数据,如果您需要它们,可以在场景 .yml 文件之上添加 YAML 文档。现在您不再需要多个文件来装饰场景了 (#65)
play.execute 不再接受原始数据字符串),消耗命令列表。引入了接受原始数据字符串的 play.execute_raw。
play.execute_command 现在接受 Python 字典(而不是字符串)
Selenium 提供程序已从 pytest-play 核心中删除,在单独的包 play_selenium 中实现。从现在开始,您必须将 provider: selenium 添加到您的 selenium 命令中
engine 的 parametrizer_class 属性不再可用(现在默认使用 parametrizer.Parametrizer)
错误修复
修复 PyPI 上的无效标记 (#55)
修复无效转义序列 (#62)。
文档和微小更改
添加示例文件夹
1.4.2 (2018-05-17)
在 Github 上的配置更改。使用 pytest 采取的相同分支策略(master 变为 main 分支,见 #56)
修复跳过的测试并添加新测试(取消选择具有关键字和标记表达式的场景)
修复 #58:如果您尝试在自动发现模式下启动 pytest-play,则不再会收到 TypeError
修复 #55:重构文本 lint 在 README.rst 上(在 pypi 上的可视化不良)
更新 README(文章和演讲链接)
为 play_json fixture 添加 DeprecationWarning。pytest-play 将基于 yaml 而不是 json(版本 >=2.0.0)。请参阅 https://github.com/pytest-dev/pytest-play/issues/5
1.4.1 (2018-04-06)
文档改进
添加 bzt/Taurus/BlazeMeter 兼容性
1.4.0 (2018-04-05)
较小的文档改进
现在自动收集和执行 test_XXX.json 文件
您可以使用pytest CLI运行测试场景 pytest test_YYY.json
引入了包含标记定义的json测试场景ini文件。对于给定的test_YYY.json场景,您可以添加一个test_YYY.ini ini文件
[pytest] markers = marker1 marker2
并使用标记表达式过滤场景 pytest -m marker1
启用了在场景ini文件中对纯json场景的参数化
[pytest] test_data = {"username": "foo"} {"username": "bar"}
您的json场景将执行两次
pytest-play现在基于您的pytest-variables文件中可选的pytest-play部分的包含内容加载一些变量。所以如果您的变量文件包含以下值
pytest-play: foo: bar date_format: YYYYMMDD
您将能够使用表达式$foo,$date_format,variables['foo']或variables['date_format']
1.3.2 (2018-02-05)
在Python表达式中添加sorted
1.3.1 (2018-01-31)
添加更多测试
更新文档
play_json fixture不再假设您有某些pytest-variables设置。不再强制
修复仅在Windows上发生的包含场景的bug(正斜杠与反斜杠和JSON解码问题)
1.3.0 (2018-01-22)
改进文档
支持拆卸回调
1.2.0 (2018-01-22)
在pytest-play中实现基于Python的命令,并弃用play_python。因此,此功能是play-python插件的直接替换。
从现在起,您不再需要安装play_python
更新文档
弃用selenium命令(它们将在单独的插件中实现,并在pytest-play >= 2.0.0中弃用)。所有您之前的脚本都将正常工作,此警告只是为了那些直接导入提供者的人。
实现跳过条件。您可以省略任何评估基于Python的跳过条件的命令的执行
1.1.0 (2018-01-16)
更新文档(添加新的pytest play插件)
支持命令提供者的默认有效载荷。对于HTTP身份验证头和常见数据库设置非常有用
1.0.0 (2018-01-10)
执行命令现在接受kwargs
执行命令现在返回命令值
完全重构include提供者(无向后兼容性)
添加play_json.get_file_contents并删除data_getter fixture(无向后兼容性)
0.3.1 (2018-01-04)
play引擎现在记录要执行的命令和错误
0.3.0 (2018-01-04)
您可以在执行命令时更新变量
您可以通过setuptools entrypoints使用来自第三方包的新可插拔命令扩展pytest-play
0.2.0 (2018-01-02)
默认情况下不再打开浏览器 pytest-play是一个通用测试引擎,也可以用于非UI测试。
因此,对于非UI测试(例如:API测试),无需打开浏览器
0.1.0 (2017-12-22)
实现可重用步骤(包括场景)
较小的文档更改
0.0.1 (2017-12-20)
首次发布
项目详细信息
pytest-play-2.3.1.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | dd19138cdd1c8baa68671c404c8581eee64623e7ff02a4cc5f586fd2198936cd |
|
MD5 | 69c1d2e2c00fd06bdeac9136ce6aa1b0 |
|
BLAKE2b-256 | 8cecb9ab32993fbc2fb612cd828d58eba9b250dab591a380c7cef1d42f2e5fd0 |