尝试编写用于REST API测试的黄瓜功能步骤。
我不确定哪种方法更好:
Given I log in with username and password
When I add one "tv" into my cart
And I check my cart
Then I should see the item "tv" is in my cart
或
Given the client authenticate with username and password
When the client send POST to "/cart/add" with body "{item: body}"
Then the response code should be "200"
And the response body should expect "{success: true}"
When the client send GET to "/cart"
Then the response code should be "200"
And the response body should expect "{"items": ["tv"]}"
当人们尝试为REST API编写黄瓜步骤时,是否有任何约定?
答案 0 :(得分:12)
我偶然发现了这篇有用的文章:http://gregbee.ch/blog/effective-api-testing-with-cucumber
总结......
Scenario: List fruit
Given the system knows about the following fruit:
| name | color |
| banana | yellow |
| strawberry | red |
When the client requests a list of fruit
Then the response is a list containing 2 fruits
And one fruit has the following attributes:
| attribute | type | value |
| name | String | banana |
| color | String | yellow |
And one fruit has the following attributes:
| attribute | type | value |
| name | String | strawberry |
| color | String | red |
根据JSON验证结果是一项棘手的工作,因为如果结果是数组,则元素的顺序可能与您在测试中验证的顺序不同。
答案 1 :(得分:7)
这是一个(足够接近)示例,实用程序员的“黄瓜书”说通过Cuke测试REST API,它似乎与你的第二个例子更紧密相关:
Feature: Addresses
In order to complete the information on the place
I need an address
Scenario: Addresses
Given the system knows about the following addresses:
[INSERT TABLE HERE or GRAB FROM DATABASE]
When client requests GET /addresses
Then the response should be JSON:
"""
[
{"venue": "foo", "address": "bar"},
{ more stuff }
]
"""
STEP DEFINITION:
Given(/^the system knows about the following addresses:$/) do |addresses|
# table is a Cucumber::Ast::Table
File.open('addresses.json', 'w') do |io|
io.write(addresses.hashes.to_json)
end
end
When(/^client requests GET (.*)$/) do |path|
@last_response = HTTParty.get('local host url goes here' + path)
end
Then /^the response should be JSON:$/ do |json|
JSON.parse(@last_response.body).should == JSON.parse(json)
end
ENV File:
require File.join(File.dirname(__FILE__), '..', '..', 'address_app')
require 'rack/test'
require 'json'
require 'sinatra'
require 'cucumber'
require 'httparty'
require 'childprocess'
require 'timeout'
server = ChildProcess.build("rackup", "--port", "9000")
server.start
Timeout.timeout(3) do
loop do
begin
HTTParty.get('local host here')
break
rescue Errno::ECONNREFUSED => try_again
sleep 0.1
end
end
end
at_exit do
server.stop
end
答案 2 :(得分:6)
我一直在使用黄瓜进行测试,更重要的是记录我在当前项目中使用rails-api
创建的API。我四处寻找可以使用的工具,最后我使用了cucumber-api-steps和json_spec的组合。它对我有用。
没有关于如何写黄瓜步骤的惯例。您编写步骤的方式取决于您希望如何使用黄瓜套件。我使用黄瓜输出作为我们的Angular JS客户端开发人员实现API客户端的参考。所以我的黄瓜步骤包含实际的JSON请求和响应以及每个场景的状态代码。这使得在发生变化时(特别是当客户端团队没有亲自到我的工作场所时)与客户端团队进行沟通非常容易。
每次我创建或更新API时,CI服务器都会将黄瓜作为构建的一部分运行,并将HTML格式的输出移动到可以在浏览器中打开的“build_artifacts”位置。客户端开发人员总是会以这种方式获得最新的引用。
我已经用blog post about creating a tested, documented and versioned JSON API写下了所有这些,希望它能以某种方式帮助你。
答案 3 :(得分:5)
Cucumber最初的意图之一是有助于其设计,它是为了弥合技术实施与了解业务需求的人之间的差距,以便非开发人员可以编写和/或理解测试描述。因此,它不适合详细的技术规格或逐个吹扫单元测试。
因此,如果这也是您使用Cucumber的原因,那么这将指向我的第一个测试说明。
实施第二个版本的测试没有什么大问题,Cucumber可以支持它。可能不需要解析大量的语句类型。但是你最终可能会对测试框架起作用,或者首先违背你使用Cucumber的理由。
至于一个约定,我不知道在实践中有足够的REST API测试来评论,我所看到的测试都没有使用Cucumber作为框架。
更新:浏览主题的SO,我确实找到了这个链接:https://github.com/jayzes/cucumber-api-steps,这与您的第二种格式更相似。
答案 4 :(得分:2)
现在有一些库用于服务器端REST测试,在 Ruby 中使用黄瓜。这是一对夫妇:
我用于黄瓜的服务器端REST测试的库是Cucumber-API-Steps。
以下是我使用'cucumber-api-steps'编写测试的方法(推荐):
@success
Scenario: Successfully add to cart
Given I am logged in
When I send a POST request to “/cart/add” with the following:
| item | body |
Then the response status should be “200”
And the JSON response should have "success" with the text "true"
When I send a GET request to “/cart”
Then the response status should be “200”
And the JSON response should be "{'items': ['tv']}"
以下是使用'cucumber-api-steps'的测试结果:
@success
Scenario: Successfully log in
Given I am logged out
When I send a POST request to “/login” with:
| username | katie@gmail.com |
| password | mypassword |
Then the response status should be “200”
And the JSON response should have "firstName" with the text "Katie"
以下是我使用'cucumber-api'编写测试的方法:
@success
Scenario: Successfully add to cart
Given I am logged in
When I send a POST request to “/cart/add”
And I set JSON request body to '{item: body}'
Then the response status should be “200”
And the response should have key “success” with value “true”
When I send a GET request to “/cart”
Then the response status should be “200”
And the response should follow "{'items': ['tv']}"
以下是使用'cucumber-api'的测试结果:
@success
Scenario: Successfully log in
Given I am logged out
When I send a POST request to “/login” with:
| username | katie@gmail.com |
| password | mypassword |
Then the response status should be “200”
And the response should have key “firstName”
should have key “firstName” with value “Katie”
。 “有价值”部分尚未完成。另一个资源是here,但它已经过时了(2011)。
答案 5 :(得分:0)
我认为第一个更好。我会把技术放在ruby类和模块中。例如,在when步骤和then步骤中的模块 cart.add(items),将 expect(cart.item).to include('items'=> a_string_matching(item)) 强>
这样,ruby类和模块可以在其他功能步骤中重用。例如,您可能有另一种方案可以将多个项目添加到购物车中,然后验证总金额。
然而,我认为第二个可以使它像技术功能。例如,所有api都需要公共/全局标题或正文请求。
答案 6 :(得分:0)
见这里:https://github.com/ctco/cukes-rest。它提供了一个Cucumber DSL来测试RESTful API。
答案 7 :(得分:0)
我会推荐你的第一个场景。
根据我自己的经验,我个人认为使用BDD作为软件交付方法所获得的最大价值就在于您将重点放在商业价值上。
换句话说,场景应该是企业想要的行为的示例,而不是技术实现。这确保了开发受到业务目标的驱动,并且可交付成果符合他们的期望。
这被称为外在发展。
系统行为的附加测试可以用来来涵盖技术要求,但我认为用自然语言编写这些内容的花费很少,这通常是费时费力的大量的情景。
我建议采用以下方法:
1)与BA和PO合作,使用非实现特定语言(如第一个示例)开发他们想要的行为示例。
2)工程师使用这些方法从测试第一种方法推动开发,将它们自动化为集成测试 - 大部分位于浏览器下方(例如针对您的REST API),最核心方案也通过浏览器(如果您正在开发一个)。
3)工程师使用单元测试TDD特征代码,直到单元测试和BDD示例都通过。