feser / json_spec
使用 PhpSpec 和 Behat 轻松处理 JSON 结构
Requires
- php: >=5.4.0
- fesor/json_matcher: ~0.2.3
Requires (Dev)
- behat/behat: ~3.0.13@stable
- fabpot/php-cs-fixer: ~0.5
- phpspec/phpspec: 2.1.*@dev
Conflicts
- behat/behat: <3.0.13
This package is not auto-updated.
Last update: 2024-09-14 15:32:22 UTC
README
Json Spec 提供了一套易于使用的匹配器,可以帮助您在 API 的 JSON 响应中轻松验证数据,减少痛苦。
如果您正在使用基于 JSON 的 REST API,会遇到一些问题
- 您不能简单地检查响应是否与给定的字符串相等,因为存在像服务器生成的 ID 或键排序这样的问题。
- 键的顺序应与您的 API 和预期的 JSON 相同。
- 匹配整个响应会破坏规格的 DRY(Don't Repeat Yourself)原则。
json_spec
通过在匹配之前对 JSON 进行规范化来解决这些问题。
让我们看一个简单的例子
json_spec
假设以下 JSON 文档是相等的。在断言之前,json_spec
会从响应 JSON 中排除 id
、created_at
和 updated_at
等键(排除键的列表可配置)。然后它会规范化 JSON(重新排序键,美化打印),然后只检查字符串相等性。这就是全部。您还可以通过给定路径匹配 JSON,而不是在规格中描述整个响应,检查 JSON 集合是否包含某些记录等等。
安装
要安装 json_spec
,您可能想使用 composer
composer require --dev fesor/json_spec
之后,您应该启用 json_spec
behat 扩展,并在您的 behat.yml
中可选地添加 json_spec 提供的上下文。例如
default:
suites:
default:
contexts:
- FeatureContext
- json_spec
extensions:
JsonSpec\Behat\Extension: ~
用法
json_spec 提供两种使用匹配器的方式
- 使用 json_spec 上下文,该上下文实现了验证 JSON 响应的步骤。此方法最适合开发人员使用功能规格作为 API 文档和测试的情况。
- 将
JsonMatcherFactory
注入到您的上下文中,以便您可以在步骤定义中使用它。此方法更可取,因为它允许您使用 BDD。有关如何编写功能规格的更多信息,请阅读Modeling by examples。
使用 json_spec
上下文
json_spec 提供了一个 Behat 上下文,该上下文实现了使用所有由 json_matcher
提供的匹配器的步骤。这对于测试您的应用程序的 JSON API 完美。
注意一点。json_spec
应该能够访问响应。如果您正在使用 Mink,那就没问题。json_spec
将从 Mink 获取响应。这意味着您要开始工作的全部工作就是只启用您的 behat.yml
中的 MinkExtension。
default:
suites:
default:
contexts:
- FeatureContext
- json_spec
extensions:
JsonSpec\Behat\Extension: ~
Behat\MinkExtension:
base_url: 'https://:8047'
sessions:
default:
goutte: ~
就这样,现在 json_spec
可以访问所有响应了。您还可以使用来自sanpii/behatch-contexts 的 behatch:rest
上下文,而不是 mink 上下文。
如果您正在使用自己的上下文,该上下文不使用 Mink,那么只需为您的上下文实现 JsonHolderAware
接口。
use \JsonSpec\Behat\Context\JsonHolderAware; use \Behat\Behat\Context\Context; class MyRestApiFeatureContext implements Context, JsonHolderAware { /** * @var \JsonSpec\Behat\JsonProvider\JsonHolder */ private $jsonHolder; /** * @When /^I request "([^"]*)"$/ */ public function iRequest($pageUrl) { // ... make request and get response body as string $this->jsonHolder->setJson($responseBody); } }
现在,您可以在功能中使用了 json_spec 步骤
Feature: User API
Background:
Given the following users exist:
| id | first_name | last_name |
| 1 | Steve | Richert |
| 2 | Catie | Richert |
And "Steve Richert" is friends with "Catie Richert"
Scenario: Index action
When I visit "/users.json"
Then the JSON response should have 2 users
And the JSON response at "0/id" should be 1
And the JSON response at "1/id" should be 2
Scenario: Show action
When I visit "/users/1.json"
Then the JSON response at "first_name" should be "Steve"
And the JSON response at "last_name" should be "Richert"
And the JSON response should have "created_at"
And the JSON response at "created_at" should be a string
And the JSON response at "friends" should be:
"""
[
{
"id": 2,
"first_name": "Catie",
"last_name": "Richert"
}
]
"""
上述背景步骤和 "visit" 步骤不是由 json_spec 提供的。其余步骤由 json_spec 提供。它们非常灵活,可以用多种不同的格式使用。
Then the JSON should be:
"""
{
"key": "value"
}
"""
Then the JSON at "path" should be:
"""
[
"entry",
"entry"
]
"""
Then the JSON should be {"key":"value"}
Then the JSON at "path" should be {"key":"value"}
Then the JSON should be ["entry","entry"]
Then the JSON at "path" should be ["entry","entry"]
Then the JSON at "path" should be "string"
Then the JSON at "path" should be 10
Then the JSON at "path" should be 10.0
Then the JSON at "path" should be 1e+1
Then the JSON at "path" should be true
Then the JSON at "path" should be false
Then the JSON at "path" should be null
Then the JSON should include:
"""
{
"key": "value"
}
"""
Then the JSON at "path" should include:
"""
[
"entry",
"entry"
]
"""
Then the JSON should include {"key":"value"}
Then the JSON at "path" should include {"key":"value"}
Then the JSON should include ["entry","entry"]
Then the JSON at "path" should include ["entry","entry"]
Then the JSON should include "string"
Then the JSON at "path" should include "string"
Then the JSON should include 10
Then the JSON at "path" should include 10
Then the JSON should include 10.0
Then the JSON at "path" should include 10.0
Then the JSON should include 1e+1
Then the JSON at "path" should include 1e+1
Then the JSON should include true
Then the JSON at "path" should include true
Then the JSON should include false
Then the JSON at "path" should include false
Then the JSON should include null
Then the JSON at "path" should include null
Then the JSON should have "path"
Then the JSON should be a hash
Then the JSON at "path" should be an array
Then the JSON at "path" should be a float
Then the JSON should have 1 entry
Then the JSON at "path" should have 2 entries
Then the JSON should have 3 keys
Then the JSON should have 4 whatevers
上述所有 "should" 的实例都可以后面跟 "not",所有 "JSON" 的实例都可以小写,并/或后面跟 "response"。
表格格式
还有一个步骤可以使用 Behat 的表格格式,并包含上述两个步骤之一。
然后JSON应该包含以下内容
| path/0 | {"key":"value"} |
| path/1 | ["entry","entry"] |
可以提供任意数量的行。上述步骤等同于
Then the JSON at "path/0" should be {"key":"value"}
And the JSON at "path/1" should be ["entry","entry"]
如果只提供了一个列
Then the JSON should have the following:
| path/0 |
| path/1 |
这等同于
Then the JSON should have "path/0"
And the JSON should have "path/1"
JSON内存
json_spec还提供了一个Behat步骤,上面没有使用。它用于记住JSON,以便在后续步骤中重复使用。你可以通过提供一个名称来“保留”全部或部分JSON。
Feature: User API
Scenario: Index action includes full user JSON
Given the following user exists:
| id | first_name | last_name |
| 1 | Steve | Richert |
And I visit "/users/1.json"
And I keep the JSON response as "USER_1"
When I visit "/users.json"
Then the JSON response should be:
"""
[
{$USER_1}
]
"""
你可以在路径下记住JSON
Given I keep the JSON response at "first_name" as "FIRST_NAME"
你可以在路径下记住JSON
Then the JSON response at "0/first_name" should be:
"""
{$FIRST_NAME}
"""
你也可以在行内记住JSON
Then the JSON response at "0/first_name" should be {$FIRST_NAME}
从版本0.2.3
开始,你可以将内存助手注入到你的特征上下文中以定义一些变量。为此,你的上下文应该实现MemoryHelperAware
接口。
更多示例
查看功能,以了解你可以使用json_spec的所有不同方式。
在你的步骤定义中使用JSON匹配器
要注入JsonMatcherFactory,你只需在你的上下文中实现JsonMatcherAware
接口,或者直接使用JsonMatcherAwareTrait
。
Scenario: User should be able to add another user in friend list Given I signed in as Bob And I view Alice's profile When I add her to my friends list Then Alice should appear in my friend list
use JsonMatcherAwareTrait; /** * @Then :user should appear in my friend list */ function userShouldAppearInFriendList(User $user) { $this ->json($this->lastResponse) ->haveSize(1) ->includes($this->serialize($user, ['short_profile']) ; }
贡献
如果你遇到任何问题,请告诉我。欢迎提交带有测试的pull request(pull request的大小不重要)。请帮助以下方面:
- 报告错误
- 建议功能
- 编写或改进文档
- 修复错别字
- 清理空白
- 重构代码
- 添加测试
- 关闭问题
如果你报告了一个错误但未提供修复,请包括一个失败的测试。
鸣谢
- json_spec - Ruby的gem,用于在RSpec和Cucumber中处理JSON。这个库主要是这个优秀库的PHP端口。