REST API тестирование огурец шаги лучшие практики

Попытка написать шаги функции огурца для теста 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?

8 ответов

Я только что наткнулся на эту полезную статью: 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 - сложная задача, поскольку, если результатом является массив, элементы могут не соответствовать порядку, который вы проверяете в тесте.

Вот (достаточно близкий) пример того, что говорит "Книга огурцов" прагматического программиста о тестировании REST API через Cuke, и, похоже, он более тесно связан с вашим вторым примером:

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

Я использовал огурец для тестирования и, что более важно, для документирования API, который я создал с помощью rails-api в моем текущем проекте. Я искал некоторые инструменты для использования, и в итоге я использовал комбинацию cucumber-api-steps и json_spec. Это хорошо сработало для меня.

Там нет соглашения о том, как написать шаги огурца. То, как вы пишете свои шаги, зависит от того, как вы хотите использовать свой набор огурцов. Я использовал вывод cucumber в качестве эталона для наших разработчиков Angular JS-клиентов для реализации API-клиента. Поэтому мои шаги с огурцом содержали реальные запросы и ответы JSON, а также код состояния для каждого сценария. Это позволило очень легко общаться с командой на стороне клиента всякий раз, когда что-то менялось (особенно, когда команда на стороне клиента физически не присутствовала на моем рабочем месте).

Каждый раз, когда я создавал или обновлял API, сервер CI запускал огурец как часть сборки и перемещал вывод в формате HTML в местоположение "build_artifacts", которое можно открыть в браузере. Разработчики на стороне клиента всегда будут получать самую свежую ссылку таким образом.

Я написал все это в своем блоге о создании проверенного, документированного и версионного API JSON, надеюсь, он вам поможет.

Одно из первоначальных намерений Cucumber, которое вносит вклад в его дизайн, заключается в том, чтобы преодолеть разрыв между технической реализацией и людьми, знающими потребности бизнеса, чтобы описания тестов могли быть написаны и / или поняты не разработчиками. Как таковой, он не очень хорошо подходит для подробных технических характеристик или испытаний на ударную установку.

Так что это указывает на ваше первое описание теста, если это также причина, по которой вы используете Cucumber.

Нет серьезных проблем с реализацией тестов, таких как вторая версия, Cucumber может ее поддерживать. Вероятно, нет большого количества типов операторов, которые вам также необходимо проанализировать. Но в итоге вы можете немного побороться с тестовой средой или пойти против вашего логического обоснования использования Cucumber.

Что касается соглашения, я не знаю достаточно тестов API REST на практике, чтобы прокомментировать, и ни один из протестированных мной тестов не использовал Cucumber в качестве фреймворка.

Обновление: просматривая SO по этой теме, я нашел ссылку на это: https://github.com/jayzes/cucumber-api-steps которая больше похожа на ваш второй формат.

Сейчас есть несколько библиотек для REST-тестирования на стороне сервера с огурцом в Ruby. Вот пара:

Библиотека, которую я использовал для REST-тестирования на стороне сервера с огурцом, - Cucumber-API-Steps.

Огурцы-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"

Огурцы-API

Вот как я написал бы ваш тест, используя '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”
  • Примечание о Cucumber-API: в настоящее время нет способа сделать should have key “firstName” with value “Katie”, Часть "с ценностью" еще не закончена.
  • Также "Follow" ожидает файл JSON

Другой ресурс здесь, но он старый (2011).

Я бы порекомендовал ваш первый сценарий.

Исходя из собственного опыта, я лично чувствую, что наибольшую ценность, которую вы получаете от использования BDD в качестве метода доставки программного обеспечения, - это когда вы делаете упор на ценность для бизнеса.

Другими словами, сценарии должны быть примерами того, какое поведение хочет бизнес, а не технической реализацией. Это гарантирует, что развитие определяется целями бизнеса, а результаты соответствуют их ожиданиям.

Это называется разработкой извне.

Дополнительные тесты поведения системы могут и должны использоваться для удовлетворения технических требований, но я думаю, что меньше затрат при написании их на естественном языке, что часто отнимает много времени и является трудоемким в большом количестве сценариев.

Я рекомендую следующий подход:

1) Работайте с BA и PO для разработки примеров поведения, которое они хотят, используя язык, не связанный с реализацией (как ваш первый пример).

2) Инженеры используют их для управления разработкой на основе тестового подхода, автоматизируя их как интеграционные тесты - большинство из которых ниже браузера (например, с вашим REST API), а большинство основных сценариев также через браузер (если вы разрабатываете один).).

3) Инженеры TDD код функции с юнит-тестами, пока не пройдут и юнит-тесты, и примеры BDD.

Смотрите здесь: https://github.com/ctco/cukes-rest. Он предоставляет Cucumber DSL для тестирования API RESTful.

Я думаю, что первый лучше. Я бы поставил технические в рубиновые классы и модули. Например, как модуль cart.add(items) в шаге when и в шаге then поместите ожидаемое (cart.item).to include('items' => a_string_matching(item))

Таким образом, классы и модули ruby ​​могут быть повторно использованы в других шагах функций. Например, может быть, у вас есть другой сценарий, который будет добавлять несколько товаров в корзину, а затем проверять общую сумму.

Тем не менее, второй 1, я думаю, может сделать его похожим на технические характеристики. Например, общий / глобальный заголовок или запрос тела ожидаются по всем API.

Другие вопросы по тегам