Qu’est-ce que le test BDD ? Exemple de cadre

Qu'est-ce que les tests BDD (Behaviour Driven Development) ?

Tests BDD (Développement piloté par le comportement) est une technique de développement logiciel agile et constitue une extension du TDD, c'est-à-dire le développement piloté par les tests. Dans BDD, les cas de test sont écrits dans un langage naturel que même les non-programmeurs peuvent lire.

Comment fonctionnent les tests BDD ?

Considérez que vous êtes chargé de créer un module de transfert de fonds dans une application Net Banking.

Il existe plusieurs façons de le tester

  1. Le transfert de fonds doit avoir lieu s'il y a suffisamment de solde sur le compte source.
  2. Le transfert de fonds doit avoir lieu si les détails de la climatisation de destination sont corrects.
  3. Le transfert de fonds doit avoir lieu si le mot de passe de la transaction/le code rsa/l'authentification de sécurité pour la transaction saisie par l'utilisateur est correct.
  4. Le transfert de fonds doit avoir lieu même s'il s'agit d'un jour férié
  5. Le transfert de fonds doit avoir lieu à une date ultérieure fixée par le titulaire du compte.

La Scénario de test devenir plus élaboré et complexe à mesure que nous considérons des fonctionnalités supplémentaires telles que le montant du transfert X pour un intervalle Y jours/mois, arrêter le transfert programmé lorsque le montant total atteint Z, et ainsi de suite

La tendance générale des développeurs est de développer des fonctionnalités et d’écrire du code de test plus tard. Comme cela est évident dans le cas ci-dessus, Cas de test le développement de ce cas est complexe et le développeur retardera Contrôle de qualité jusqu'à la sortie, après quoi il effectuera des tests rapides mais inefficaces.

Pour surmonter ce problème (Behaviour Driven Development), BDD a été conçu. Cela facilite l'ensemble du processus de test pour un développeur

En BDD, tout ce que vous écrivez doit être placé dans Étant donné-quand-alors pas. Considérons le même exemple ci-dessus dans BDD

Given that a fund transfer module in net banking application has been developed
And I am accessing it with proper authentication
WhenI shall transfer with enough balance in my source account
Or I shall transfer on a Bank Holiday
Or I shall transfer on a future date
And destination a/c details are correct
And transaction password/rsa code / security authentication for the transaction is correct
And press or click send button
Then amount must be transferred
And the event will be logged in log file

N'est-il pas facile d'écrire, de lire et de comprendre ? Il couvre tous les cas de test possibles pour le module de transfert de fonds et peut être facilement modifié pour en accueillir davantage. En outre, cela ressemble davantage à la rédaction d'une documentation pour le module de transfert de fonds.

Qu'est-ce que les tests d'API REST ?

Comme REST est devenu un style très populaire pour créer des API de nos jours, il est devenu tout aussi important d'automatiser les cas de test de l'API REST ainsi que les cas de test de l'interface utilisateur. Donc en gros, ces REST Test d'API implique de tester les actions CRUD (Create-Read-Update-Delete) avec les méthodes POST, GET, PUT et DELETE respectivement.

Qu'est-ce que le comportement ?

Le comportement est l'un des plus populaires Python Cadres de tests BDD.

Voyons comment fonctionne Behave :

Les fichiers de fonctionnalités sont rédigés par votre analyste commercial/sponsor/quiconque contenant vos scénarios de comportement. Il a un format en langage naturel décrivant une fonctionnalité ou une partie d'une fonctionnalité avec des exemples représentatifs des résultats attendus.

Ces étapes de scénario sont mappées avec des implémentations d'étapes écrites en Python.

Et en option, il existe des contrôles environnementaux (code à exécuter avant et après les étapes, scénarios, fonctionnalités ou tout le match de tir).

Commençons par la configuration de notre framework de test d'automatisation avec Behave :

Configuration du cadre de test BDD Windows

Installation:

Configuration du projet :

  • Créer un nouveau projet
  • Créez la structure de répertoire suivante :

Configuration du projet

Fichiers de fonctionnalités :

Alors construisons notre fichier de fonctionnalités Sample_REST_API_Testing.feature ayant la fonctionnalité d'effectuer des opérations CRUD sur le service « posts ».

Dans notre exemple, j'ai utilisé http://jsonplaceholder.typicode.com/ publie un exemple de service REST.

Exemple de scénario POST

Scenario: POST post example ->Here we are considering creating new post item using 'posts' service
Given: I set post posts API endpoint ->This is prerequisite for the test which is setting URL of posts service
When: I set HEADER param request content type as "application/json."
And set request body
And send POST HTTP request ->This is actual test step of sending a post request
Then: Then I receive valid HTPP response code 201 
And Response body "POST" is non-empty-> This is verification of response body	

De même, vous pouvez écrire les scénarios restants comme suit :

Configuration du projet

Sample_REST_API_Testing.feature

Feature: Test CRUD methods in Sample REST API testing framework

Background:
	Given I set sample REST API url

Scenario: POST post example
  Given I Set POST posts api endpoint
 When I Set HEADER param request content type as "application/json." 
    And Set request Body
 And Send a POST HTTP request 
 Then I receive valid HTTP response code 201
    And Response BODY "POST" is non-empty. 


Scenario: GET posts example
  Given I Set GET posts api endpoint "1"
  When I Set HEADER param request content type as "application/json." 
	And Send GET HTTP request
  Then I receive valid HTTP response code 200 for "GET." 
	And Response BODY "GET" is non-empty


Scenario: UPDATE posts example
  Given I Set PUT posts api endpoint for "1"
  When I Set Update request Body
	And Send PUT HTTP request
  Then I receive valid HTTP response code 200 for "PUT." 
	And Response BODY "PUT" is non-empty


Scenario: DELETE posts example
  Given I Set DELETE posts api endpoint for "1"
  When I Send DELETE HTTP request
  Then I receive valid HTTP response code 200 for "DELETE." 

Étapes de mise en œuvre

Désormais, pour les étapes de fonctionnalité utilisées dans les scénarios ci-dessus, vous pouvez écrire des implémentations dans Python fichiers dans le répertoire « étapes ».

Le framework Behave identifie la fonction Step par des décorateurs correspondant au prédicat du fichier de fonctionnalités. Par exemple, le prédicat donné dans le scénario de fichier de fonctionnalités recherche la fonction d'étape dont le décorateur est « donné ». Une correspondance similaire se produit pour When et Then. Mais dans le cas de « Mais », « Et », la fonction Step prend le décorateur de la même manière que l'étape précédente. Par exemple, si « Et » vient pour Étant donné, le décorateur de fonction d'étape correspondant est @given.

Par exemple, lorsque l'étape POST peut être implémentée comme suit :

@when (u'I Set HEADER param request content type as "{header_conent_type}"')
Mapping of When, here notice “application/json” is been passed from feature file for "{header_conent_type}” . This is called as parameterization


def step_impl (context, header_conent_type):
This is step implementation method signature

request_headers['Content-Type'] = header_conent_type
Step implementation code, here you will be setting content type for request header

De même, l'implémentation d'autres étapes dans le fichier step python ressemblera à ceci :

Étapes de mise en œuvre

sample_step_implementation.py

from behave import given, when, then, step
import requests

api_endpoints = {}
request_headers = {}
response_codes ={}
response_texts={}
request_bodies = {}
api_url=None

@given(u'I set sample REST API url')
def step_impl(context):
    global api_url
    api_url = 'http://jsonplaceholder.typicode.com'

# START POST Scenario
@given(u'I Set POST posts api endpoint')
def step_impl(context):
    api_endpoints['POST_URL'] = api_url+'/posts'
    print('url :'+api_endpoints['POST_URL'])

@when(u'I Set HEADER param request content type as "{header_conent_type}"')
def step_impl(context, header_conent_type):
    request_headers['Content-Type'] = header_conent_type

#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Set request Body')
def step_impl(context):
    request_bodies['POST']={"title": "foo","body": "bar","userId": "1"}

#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Send POST HTTP request')
def step_impl(context):
    # sending get request and saving response as response object
    response = requests.post(url=api_endpoints['POST_URL'], json=request_bodies['POST'], headers=request_headers)
    #response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    # extracting response text
    response_texts['POST']=response.text
    print("post response :"+response.text)
    # extracting response status_code
    statuscode = response.status_code
    response_codes['POST'] = statuscode

@then(u'I receive valid HTTP response code 201')
def step_impl(context):
    print('Post rep code ;'+str(response_codes['POST']))
    assert response_codes['POST'] is 201
# END POST Scenario

# START GET Scenario
@given(u'I Set GET posts api endpoint "{id}"')
def step_impl(context,id):
    api_endpoints['GET_URL'] = api_url+'/posts/'+id
    print('url :'+api_endpoints['GET_URL'])

#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Send GET HTTP request')
def step_impl(context):
    # sending get request and saving response as response object
    response = requests.get(url=api_endpoints['GET_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    # extracting response text
    response_texts['GET']=response.text
    # extracting response status_code
    statuscode = response.status_code
    response_codes['GET'] = statuscode

@then(u'I receive valid HTTP response code 200 for "{request_name}"')
def step_impl(context,request_name):
    print('Get rep code for '+request_name+':'+ str(response_codes[request_name]))
    assert response_codes[request_name] is 200

@then(u'Response BODY "{request_name}" is non-empty')
def step_impl(context,request_name):
    print('request_name: '+request_name)
    print(response_texts)
    assert response_texts[request_name] is not None
# END GET Scenario

#START PUT/UPDATE
@given(u'I Set PUT posts api endpoint for "{id}"')
def step_impl(context,id):
    api_endpoints['PUT_URL'] = api_url + '/posts/'+id
    print('url :' + api_endpoints['PUT_URL'])

@when(u'I Set Update request Body')
def step_impl(context):
    request_bodies['PUT']={"title": "foo","body": "bar","userId": "1","id": "1"}

@when(u'Send PUT HTTP request')
def step_impl(context):
    # sending get request and saving response as response object  # response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    response = requests.put(url=api_endpoints['PUT_URL'], json=request_bodies['PUT'], headers=request_headers)
    # extracting response text
    response_texts['PUT'] = response.text
    print("update response :" + response.text)
    # extracting response status_code
    statuscode = response.status_code
    response_codes['PUT'] = statuscode
#END PUT/UPDATE

#START DELETE
@given(u'I Set DELETE posts api endpoint for "{id}"')
def step_impl(context,id):
    api_endpoints['DELETE_URL'] = api_url + '/posts/'+id
    print('url :' + api_endpoints['DELETE_URL'])

@when(u'I Send DELETE HTTP request')
def step_impl(context):
    # sending get request and saving response as response object
    response = requests.delete(url=api_endpoints['DELETE_URL'])
    # response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    # extracting response text
    response_texts['DELETE'] = response.text
    print("DELETE response :" + response.text)
    # extracting response status_code
    statuscode = response.status_code
    response_codes['DELETE'] = statuscode
#END DELETE

Exécution des tests

Maintenant, nous avons terminé notre partie développement de script de test, alors exécutons nos tests :

Exécutez la commande suivante à l'invite de commande pour exécuter notre fichier de fonctionnalités

C: \Programmes\Python\Python37>comporte-toi -f joliment C:\ \features\feature_files_folder\Sample_REST_API_Testing.feature

Cela affichera les résultats de l'exécution du test comme suit :

Exécuter les tests

Affichage du rapport sur la console

Voyons encore une chose sympa ici.

Comme les utilisateurs préfèrent toujours voir les résultats des tests dans un format plus lisible et présentable, créons des rapports au format HTML avec l'aide d'Allure.

Rapports

Tout d’abord, vous devez installer le formateur Allure Behave [https://docs.qameta.io/allure-report/]:

Et maintenant exécutez la commande suivante :

Pour les rapports

>se comporter -f json -o Sample_REST_API_Testing.feature

> attrait servir

Cela générera votre rapport de résultats de test dans un format présentable et informatif comme celui-ci :

Rapports

Rapport de test au format HTML

Rapport de test au format HTML

Rapport de test affichant le résultat du scénario individuel

Résumé

  • BDD est un développement axé sur le comportement. C'est l'une des techniques de développement logiciel agile.
  • REST est devenu un style très populaire pour créer des API de nos jours, il est devenu tout aussi important d'automatiser les cas de test de l'API REST ainsi que les cas de test de l'interface utilisateur.
  • BDD a un format en langage naturel décrivant une fonctionnalité ou une partie d'une fonctionnalité avec des exemples représentatifs des résultats attendus
  • Le framework Behave identifie la fonction Step par les décorateurs correspondant au prédicat du fichier de fonctionnalités
  • Exemples de cadres de tests BDD : 1) Cucumber 2) SpecFlow 3) Quantique 4) JBehave 5) Codeception