24

Trying to write up cucumber feature steps for REST API test.

I am not sure which approach is better:

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

or

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"]}"

Is there any convention to follow when people trying to write cucumber steps for REST API?

4

8 回答 8

14

我刚刚偶然发现了这篇有用的文章:https ://www.gregbeech.com/2014/01/19/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 验证结果是一件棘手的事情,因为如果结果是一个数组,则元素的顺序可能与您在测试中验证的顺序不同。

编辑:使用 finderAUT 的评论更新链接。谢谢!

于 2014-05-09T17:08:39.453 回答
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
于 2013-06-05T19:20:47.970 回答
6

我一直在使用 cucumber 进行测试,更重要的是记录我rails-api在当前项目中使用的 API。我四处寻找一些要使用的工具,最后我使用了cucumber-api-stepsjson_spec的组合。它对我来说效果很好。

关于如何编写黄瓜步骤没有约定。你编写步骤的方式取决于你想如何使用你的黄瓜套件。我使用黄瓜输出作为我们的 Angular JS 客户端开发人员实现 API 客户端的参考。所以我的黄瓜步骤包含实际的 JSON 请求和响应以及每个场景的状态代码。这使得在发生变化时与客户端团队进行沟通变得非常容易(尤其是当客户端团队不在我的工作场所时)。

每次我创建或更新 API 时,CI 服务器都会在构建过程中运行 cucumber,并将 HTML 格式的输出移动到可以在浏览器中打开的“build_artifacts”位置。客户端开发人员总是会以这种方式获得最新的参考。

我已经在一篇关于创建经过测试、记录和版本化的 JSON API的博客文章中写下了所有这些内容,希望它对您有所帮助。

于 2013-08-02T09:09:23.810 回答
5

Cucumber 的设计初衷之一是弥合技术实现与了解业务需求的人员之间的差距,以便非开发人员可以编写和/或理解测试描述。因此,它不太适合详细的技术规范或逐个单元测试。

如果这也是您使用 Cucumber 的原因,那么这将指向您的第一个测试描述。

像第二个版本那样实现测试没有大问题,Cucumber 可以支持。您可能也不需要解析大量的语句类型。但是你最终可能会与测试框架发生一点冲突,或者违背你最初使用 Cucumber 的理由。

至于约定,我不知道实践中是否有足够的 REST API 测试可以评论,而且我所看到的测试中没有一个使用 Cucumber 作为框架。

更新:浏览有关该主题的 SO,我确实找到了指向此的链接:https ://github.com/jayzes/cucumber-api-steps ,它与您的第二种格式更相似。

于 2013-05-24T18:57:44.897 回答
3
于 2016-08-31T19:55:49.543 回答
1

我会推荐你​​的第一个场景。

根据我自己的经验,我个人认为,将 BDD 用作软件交付方法所获得的最大价值在于您将重点放在业务价值上。

换句话说,场景应该是企业想要什么行为的例子,而不是技术实现。这样可以确保开发由业务目标驱动,并且可交付成果符合他们的期望。

这被称为由外而内的开发。

系统行为的额外测试可以而且应该用于覆盖技术要求,但我认为花费精力用自然语言编写这些测试的价值较小,这在大量场景中通常既耗时又费力。

我推荐以下方法:

1) 与 BA 和 PO 合作,使用非实现特定语言(如您的第一个示例)开发他们想要的行为示例。

2)工程师使用这些从测试优先的方法驱动开发,将它们作为集成测试自动化 - 大多数在浏览器下方(例如针对您的 REST API)和最核心的场景也通过浏览器(如果您正在开发一个)。

3) 工程师使用单元测试对特性代码进行TDD,直到单元测试和BDD 示例都通过。

于 2017-05-05T08:44:22.930 回答
0

我觉得第一个更好。我会将技术放在 ruby​​ 类和模块中。例如,在 when 步骤中的模块cart.add(items)和 then 步骤中 put expect(cart.item).to include('items' => a_string_matching(item))

这样,ruby 类和模块可以在其他功能步骤中重用。例如,也许您有另一种情况,将多个项目添加到购物车中,然后验证总金额。

但是,我认为第二个 1 可以使它像技术功能一样。例如,所有 api 都需要公共/全局标头或正文请求。

于 2016-01-11T03:19:21.923 回答
0

见这里:https ://github.com/ctco/cukes-rest 。它提供了一个 Cucumber DSL 来测试 RESTful API。

于 2016-07-12T09:37:40.230 回答