web-dev-qa-db-fra.com

REST Meilleures pratiques pour les étapes de test de concombre API

Essayer de rédiger les étapes de la fonctionnalité de concombre pour le test de l'API REST.

Je ne sais pas quelle approche est la meilleure:

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

ou

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

Existe-t-il une convention à suivre lorsque des personnes essaient d'écrire des étapes de concombre pour l'API REST?

18
ccy

Je viens de tomber sur cet article utile: http://gregbee.ch/blog/effective-api-testing-with-cucumber

Résumer...

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        |

Valider un résultat par rapport à JSON est une tâche délicate, car si le résultat est un tableau, les éléments peuvent ne pas correspondre au même ordre que celui utilisé pour la validation dans le test. 

12
bitlather

Voici un exemple (assez proche) de ce que le programmeur pragmatique "The Cucumber Book" dit à propos du test des API REST via Cuke, et il semble se rapporter davantage à votre deuxième exemple:

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
7
Whitney Imura

J'ai utilisé concombre pour tester et surtout pour documenter l'API que j'ai créée à l'aide de Rails-api dans mon projet actuel. J'ai cherché des outils à utiliser et j'ai fini par utiliser une combinaison de concombre-api-étapes et json_spec . Ça a bien marché pour moi.

Il n'y a pas de convention sur la façon d'écrire les étapes de concombre. La façon dont vous écrivez vos étapes dépend de la manière dont vous souhaitez utiliser votre suite de concombres. J'ai utilisé la sortie concombre comme référence pour nos devs clients JS Angular pour implémenter le client API. Ainsi, mes étapes relatives aux concombres contenaient les demandes et les réponses JSON réelles ainsi que le code d'état de chaque scénario. Cela rendait très facile la communication avec une équipe côté client chaque fois que quelque chose changeait (en particulier lorsque l'équipe côté client n'était pas physiquement présente sur mon lieu de travail).

Chaque fois que je créerais ou mettrais à jour une API, le serveur CI exécuterait un concombre dans le cadre de la construction et déplacerait la sortie au format HTML vers un emplacement "build_artifacts" pouvant être ouvert dans le navigateur. Les développeurs côté client obtiendraient toujours la référence la plus récente de cette façon.

J'ai écrit tout cela dans un article de blog sur la création d'une API JSON testée, documentée et versionnée , j'espère que cela vous aidera d'une manière ou d'une autre.

6
Emil

L'un des objectifs initiaux de Cucumber, qui contribue à sa conception, est de combler le fossé entre la mise en œuvre technique et les personnes connaissant les besoins de l'entreprise, afin que les descriptions de test puissent être écrites et/ou comprises par des non-développeurs. En tant que tel, il n’est pas parfaitement adapté aux spécifications techniques détaillées ou aux tests unitaires soufflés. 

Cela m'indiquerait donc la description de votre premier test, si c'est aussi la raison pour laquelle vous utilisez Cucumber.

Il n’ya pas de problème majeur lors de la mise en oeuvre de tests comme la deuxième version, Cucumber peut le supporter. Il n’ya probablement pas beaucoup de types d’instruction à analyser. Mais vous pourriez finir par vous battre un peu contre le cadre de test, ou aller à l’encontre de votre logique d’utilisation du concombre en premier lieu.

En ce qui concerne une convention, je ne connais pas suffisamment de tests d’API REST en pratique pour pouvoir faire des commentaires, et aucun des tests que j’ai vu tester n’a utilisé Cucumber comme structure.

Mise à jour: en parcourant SO sur le sujet, j'ai trouvé un lien vers ceci: https://github.com/jayzes/cucumber-api-steps , qui ressemble davantage à votre deuxième format.

5
Neil Slater

Il existe maintenant quelques bibliothèques pour les tests REST côté serveur avec concombre dans Ruby. Voici un couple:

La bibliothèque que j'ai utilisée pour les tests côté serveur REST avec concombre est Cucumber-API-Steps

Cucumber-API-Steps

Voici comment j'écrirais votre test en utilisant 'concombre-api-étapes'} _ (Recommandé):

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

Et voici à quoi mes tests ressemblent en utilisant 'concombre-api-étapes':

@success
Scenario: Successfully log in
  Given I am logged out
  When I send a POST request to “/login” with:
       | username | [email protected] |
       | password | mypassword |
  Then the response status should be “200”
  And the JSON response should have "firstName" with the text "Katie"

API concombre

Voici comment j'écrirais votre test en utilisant 'api concombre':

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

Et voici à quoi ressemblent mes tests avec 'concombre-api':

@success
Scenario: Successfully log in
  Given I am logged out
  When I send a POST request to “/login” with:
       | username | [email protected] |
       | password | mypassword |
  Then the response status should be “200”
  And the response should have key “firstName”
  • Note sur Cucumber-API: Il n’existe actuellement aucun moyen de faire should have key “firstName” with value “Katie”. La partie "avec valeur" n'a pas encore été faite.
  • Aussi "Follow" attend un fichier JSON

Une autre ressource est ici , mais elle est ancienne (2011).

1
Katie S

Je recommanderais votre premier scénario.

De par ma propre expérience, j'estime personnellement que l'utilisation de BDD en tant que méthode de fourniture de logiciel constitue le plus grand avantage que vous obtenez lorsque vous mettez l'accent sur la valeur commerciale.

En d'autres termes, les scénarios doivent être des exemples du comportement souhaité par l'entreprise, plutôt que la mise en œuvre technique. Cela garantit que le développement est axé sur les objectifs de l'entreprise et que les produits livrables correspondent à ses attentes.

C'est ce qu'on appelle le développement externe.

Des tests supplémentaires du comportement du système peuvent et devraient être utilisés pour couvrir les exigences techniques, mais je pense que les efforts de dépense réduisent leur coût en langage naturel, ce qui prend souvent beaucoup de temps et est laborieux dans un grand nombre de scénarios.

Je recommande l'approche suivante:

1) Travaillez avec les BA et les OP pour développer des exemples du comportement qu'ils souhaitent utiliser à l'aide d'un langage non spécifique à la mise en œuvre (comme votre premier exemple). 

2) Les ingénieurs les utilisent pour piloter le développement à partir d’une première approche de test, en les automatisant en tant que tests d’intégration - la majorité se trouvant en dessous du navigateur (par rapport à votre API REST par exemple) et les scénarios les plus fondamentaux également via le navigateur (si nécessaire). vous en développez un). 

3) Les ingénieurs TDD le code de fonction avec les tests unitaires jusqu'à ce que les tests unitaires et les exemples BDD réussissent. 

0
ADP

Je pense que le premier est meilleur. Je mettrais la technique dans les classes et les modules Ruby. E.g comme module cart.add (items) dans l'étape When et dans l'étape then put expect (cart.item) .to include ('items' => a_string_matching (item))

Grâce à cela, les classes et modules Ruby peuvent être réutilisés dans d'autres étapes de fonctionnalités. Par exemple, vous avez peut-être un autre scénario qui ajouterait plusieurs articles dans le panier, puis validerait le montant total. 

Cependant, je pense que le second 1 peut en faire une caractéristique technique. Une requête d'entête ou de corps commune/globale similaire à E.g est attendue pour l'ensemble de l'api.

0
Steve Chew

Voir ici: https://github.com/ctco/cukes-rest . Il fournit un DSL de concombre pour tester les API RESTful.

0
Bernd