Hva er BDD-testing? Rammeeksempel

Hva er BDD-testing (Behavior Driven Development)?

BDD (Atferdsdrevet utvikling) Testing er en teknikk for smidig programvareutvikling og er en forlengelse av TDD, dvs. Test Driven Development. I BDD er testcaser skrevet pรฅ et naturlig sprรฅk som selv ikke-programmerere kan lese.

Hvordan fungerer BDD-testing?

Tenk pรฅ at du har fรฅtt i oppdrag รฅ opprette modul for overfรธring av midler i en nettbankapplikasjon.

Det er flere mรฅter รฅ teste det pรฅ

  1. Fondsoverfรธring bรธr finne sted hvis det er nok saldo pรฅ kildekontoen
  2. Fondsoverfรธring bรธr finne sted hvis destinasjonsklimadetaljer er korrekte
  3. Fondsoverfรธring bรธr finne sted hvis transaksjonspassord / rsa-kode / sikkerhetsautentisering for transaksjonen angitt av bruker er riktig
  4. Pengeoverfรธring bรธr finne sted selv om det er en helligdag
  5. Fondsoverfรธring bรธr finne sted pรฅ en fremtidig dato som er fastsatt av kontoinnehaveren

Ocuco Testscenario bli mer forseggjort og kompleks ettersom vi vurderer tilleggsfunksjoner som overfรธringsbelรธp X for et intervall Y dager/mรฅneder , stoppe tidsplanoverfรธring nรฅr totalbelรธpet nรฅr Z , og sรฅ videre

Den generelle tendensen til utviklere er รฅ utvikle funksjoner og skrive testkode senere. Som det fremgรฅr av saken ovenfor, Testsak Utviklingen for denne saken er kompleks og utvikleren vil utsette Testing til utgivelsen, da vil han gjรธre rask, men ineffektiv testing.

For รฅ overvinne dette problemet (Behavior Driven Development) ble BDD unnfanget. Det gjรธr hele testprosessen enkel for en utvikler

I BDD mรฅ det du skriver gรฅ inn pรฅ Gitt-Nรฅr-Da trinn. La oss vurdere det samme eksemplet ovenfor i 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

Er det ikke lett รฅ skrive og lese og forstรฅ? Den dekker alle mulige testtilfeller for fondsoverfรธringsmodulen og kan enkelt modifiseres for รฅ fรฅ plass til flere. Dessuten er det mer som รฅ skrive dokumentasjon for fondsoverfรธringsmodulen.

Hva er REST API-testing?

Ettersom REST har blitt en ganske populรฆr stil for รฅ bygge API-er i dag, har det blitt like viktig รฅ automatisere REST API-testsaker sammen med UI-testsaker. Sรฅ i bunn og grunn, disse HVILER API-testing innebรฆrer testing av CRUD-handlinger (Create-Read-Update-Delete) med metodene henholdsvis POST, GET, PUT og DELETE.

Hva er Behave?

Behave er en av de populรฆre Python BDD-testrammeverk.

La oss se hvordan Behave fungerer:

Funksjonsfiler er skrevet av din forretningsanalytiker / sponsor / hvem som helst med dine atferdsscenarier i den. Den har et naturlig sprรฅkformat som beskriver en funksjon eller en del av en funksjon med representative eksempler pรฅ forventede resultater

Disse scenarietrinnene er kartlagt med trinnimplementeringer skrevet inn Python.

Og valgfritt er det noen miljรธkontroller (kode som skal kjรธres fรธr og etter trinn, scenarier, funksjoner eller hele skytekampen).

La oss komme i gang med oppsettet av vรฅrt automatiseringstestrammeverk med Behave:

Sette opp BDD Testing Framework Behave on Windows

Installasjon:

Prosjektoppsett:

  • Lag et nytt prosjekt
  • Lag fรธlgende katalogstruktur:

Prosjektoppsett

Funksjonsfiler:

Sรฅ la oss bygge funksjonsfilen vรฅr Sample_REST_API_Testing.feature har funksjon som รฅ utfรธre CRUD-operasjoner pรฅ 'posts'-tjenesten.

I vรฅrt eksempel har jeg brukt http://jsonplaceholder.typicode.com/ legger inn eksempel REST Service.

Eksempel POST-scenario

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	

Pรฅ samme mรฅte kan du skrive de resterende scenariene som fรธlger:

Prosjektoppsett

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." 

Trinn Implementering

Nรฅ, for funksjonstrinn brukt i scenariene ovenfor, kan du skrive implementeringer i Python filer i "trinn"-katalogen.

Behave-rammeverket identifiserer Step-funksjonen ved at dekoratรธrer matcher med funksjonsfilpredikatet. For eksempel sรธker gitt predikat i funksjonsfil Scenario etter trinnfunksjon som har dekorator "gitt." Tilsvarende samsvar skjer for Nรฅr og Da. Men i tilfellet 'Men', 'Og', tar trinn-funksjonen dekorator samme som det foregรฅende trinnet. For eksempel, hvis 'And' kommer for gitt, er matchende trinnfunksjonsdekorator @gitt.

For eksempel, nรฅr trinn for POST kan implementeres som fรธlger:

@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

Pรฅ samme mรฅte vil implementeringen av andre trinn i step python-filen se slik ut:

Trinn Implementering

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

Kjรธrer testene

Nรฅ er vi ferdige med utviklingsdelen for testskript, sรฅ la oss kjรธre testene vรฅre:

Utfรธr fรธlgende kommando pรฅ ledeteksten for รฅ kjรธre funksjonsfilen vรฅr

C: \Programmer\Python\Python37>oppfรธre seg -f pen C:\ \features\feature_files_mappe\Sample_REST_API_Testing.feature

Dette vil vise testutfรธrelsesresultater som fรธlger:

Kjรธrer testene

Rapporter visning pรฅ konsollen

La oss se en kul ting til her.

Siden brukere alltid foretrekker รฅ se testresultater i et mer lesbart og presentabelt format, la oss ha rapporter i HTML-format ved hjelp av Allure.

Rapporter

Fรธrst mรฅ du installere Allure Behave formatter [https://docs.qameta.io/allure-report/]:

Og kjรธr nรฅ fรธlgende kommando:

For rapporter

>oppfรธre seg -f json -o Sample_REST_API_Testing.feature

> lokke tjene

Dette vil generere testresultatrapporten din i presentabelt og informativt format som dette:

Rapporter

Testrapport i HTML-format

Testrapport i HTML-format

Testrapport som viser individuelle scenarioresultater

Sammendrag

  • BDD er atferdsdrevet utvikling. Det er en av teknikkene for smidig programvareutvikling.
  • REST har blitt en ganske populรฆr stil for รฅ bygge API-er i dag, det har blitt like viktig รฅ automatisere REST API-testsaker sammen med UI-testsaker.
  • BDD har et naturlig sprรฅkformat som beskriver en funksjon eller en del av en funksjon med representative eksempler pรฅ forventede resultater
  • Behave-rammeverket identifiserer Step-funksjonen ved at dekoratรธrer matcher med funksjonsfilpredikatet
  • Eksempler pรฅ BDD-testrammeverk: 1) Cucumber 2) SpecFlow 3) Quantum 4) JBehave 5) Codeception

Oppsummer dette innlegget med: