Co to jest testowanie BDD? Przykład ramowy

Co to jest test BDD (rozwój zorientowany na zachowanie)?

Testowanie BDD (rozwój zorientowany na zachowanie). jest techniką zwinnego tworzenia oprogramowania i stanowi rozwinięcie TDD, czyli Test Driven Development. W BDD przypadki testowe są pisane w języku naturalnym, zrozumiałym nawet dla osób niebędących programistami.

Jak działa testowanie BDD?

Załóżmy, że przydzielono Ci zadanie utworzenia modułu Transferu Funduszy w aplikacji Net Banking.

Można to przetestować na wiele sposobów

  1. Transfer środków powinien nastąpić, jeśli na rachunku źródłowym jest wystarczające saldo
  2. Przelew środków powinien zostać zrealizowany, jeśli dane rachunku docelowego są prawidłowe
  3. Przelew środków powinien nastąpić w przypadku, gdy hasło transakcji / kod rsa / uwierzytelnienie zabezpieczające dla transakcji wprowadzone przez użytkownika jest prawidłowe
  4. Transfer środków powinien nastąpić nawet jeśli jest to święto państwowe
  5. Transfer środków powinien nastąpić w przyszłym terminie określonym przez posiadacza rachunku

Scenariusz testowy stają się bardziej rozbudowane i złożone, gdy bierzemy pod uwagę dodatkowe funkcje, takie jak kwota przelewu X na okres Y dni/miesięcy, zatrzymanie harmonogramu przelewu, gdy łączna kwota osiągnie Z itd.

Ogólną tendencją programistów jest rozwijanie funkcji i pisanie kodu testowego później. Jak widać w powyższym przypadku, Przypadek testowy rozwój w tym przypadku jest skomplikowany i deweloper będzie odkładał Testowanie aż do wydania, po czym przeprowadzi szybkie, ale nieskuteczne testy.

Aby przezwyciężyć ten problem (rozwój oparty na zachowaniu), stworzono BDD. Ułatwia to programiście cały proces testowania

W BDD wszystko, co napiszesz, musi zostać uwzględnione Biorąc pod uwagę-Kiedy-Wtedy kroki. Rozważmy ten sam przykład powyżej w 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

Czy nie jest łatwo pisać, czytać i rozumieć? Obejmuje wszystkie możliwe przypadki testowe modułu transferu środków i można go łatwo modyfikować, aby uwzględnić więcej. Przypomina to raczej pisanie dokumentacji do modułu transferu środków.

Co to jest testowanie API REST?

Ponieważ REST stał się obecnie dość popularnym stylem budowania interfejsów API, równie ważna stała się automatyzacja przypadków testowych interfejsu API REST wraz z przypadkami testowymi interfejsu użytkownika. Zasadniczo te REST Testowanie API obejmuje testowanie akcji CRUD (Create-Read-Update-Delete) odpowiednio metodami POST, GET, PUT i DELETE.

Co to jest Zachowaj się?

Zachowaj się jest jednym z popularnych Python Frameworki testowe BDD.

Zobaczmy, jak działa Behave:

Pliki funkcji są zapisywane przez Twojego Analityka Biznesowego / Sponsora / kogokolwiek i zawierają w nich Twoje scenariusze zachowań. Ma format języka naturalnego opisujący cechę lub część cechy z reprezentatywnymi przykładami oczekiwanych wyników

Te kroki scenariusza są mapowane z zapisanymi implementacjami kroków Python.

Opcjonalnie istnieją pewne kontrole środowiskowe (kod uruchamiany przed i po etapach, scenariusze, funkcje lub cały mecz).

Zacznijmy od konfiguracji naszego frameworku testów automatycznych za pomocą Behave:

Konfigurowanie środowiska testowego BDD Zachowaj włączone Windows

Instalacja:

Konfiguracja projektu:

  • Utwórz nowy projekt
  • Utwórz następującą strukturę katalogów:

Konfiguracja projektu

Pliki funkcji:

Zbudujmy więc nasz plik funkcji Sample_REST_API_Testing.feature mająca funkcję Wykonywania operacji CRUD w usłudze 'poczty'.

W naszym przykładzie użyłem http://jsonplaceholder.typicode.com/ publikuje przykładową usługę REST.

Przykładowy scenariusz 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	

Podobnie możesz napisać pozostałe Scenariusze w następujący sposób:

Konfiguracja projektu

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

Wdrożenie kroków

Teraz w przypadku kroków funkcji używanych w powyższych scenariuszach możesz zapisać implementacje w Python pliki w katalogu „steps”.

Struktura Behave identyfikuje funkcję Step poprzez dopasowanie dekoratorów do predykatu pliku funkcji. Na przykład, podany predykat w pliku funkcji Scenariusz wyszukuje funkcję kroku mającą dekorator „podany”. Podobne dopasowanie ma miejsce w przypadku „When” i „Then”. Ale w przypadku „Ale”, „I” funkcja Step przyjmuje dekorator tak samo, jak w poprzednim kroku. Na przykład, jeśli „And” pojawia się w przypadku Biorąc, dekoratorem pasującej funkcji kroku jest @podany.

Na przykład, gdy krok POST można zaimplementować w następujący sposób:

@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

Podobnie implementacja pozostałych kroków w pliku Pythona krokowego będzie wyglądać następująco:

Wdrożenie kroków

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

Uruchamianie testów

Skończyliśmy już część dotyczącą tworzenia skryptu testowego, więc przeprowadźmy nasze testy:

Wykonaj następujące polecenie w wierszu poleceń, aby uruchomić nasz plik funkcji

C: \Programy\Python\Python37>zachowuj się -f ładnie C:\ \features\folder_plików_funkcji\Sample_REST_API_Testing.feature

Spowoduje to wyświetlenie wyników wykonania testu w następujący sposób:

Uruchamianie testów

Wyświetlanie raportu na konsoli

Zobaczmy jeszcze jedną fajną rzecz.

Ponieważ użytkownicy zawsze wolą przeglądać wyniki testów w bardziej czytelnej i przejrzystej formie, utwórzmy raporty w formacie HTML za pomocą Allure.

Raporty

Najpierw musisz zainstalować formatyzator Allure Behave [https://docs.qameta.io/allure-report/]:

A teraz wykonaj następujące polecenie:

Do raportów

>zachowuj się -f json -o Sample_REST_API_Testing.feature

> służyć urokowi

Spowoduje to wygenerowanie raportu z wyników testu w prezentacyjnym i informacyjnym formacie, takim jak ten:

Raporty

Raport z testu w formacie HTML

Raport z testu w formacie HTML

Raport z testu wyświetlający wynik indywidualnego scenariusza

Podsumowanie

  • BDD to rozwój oparty na zachowaniu. Jest to jedna z technik zwinnego wytwarzania oprogramowania.
  • REST stał się obecnie dość popularnym stylem budowania interfejsów API, równie ważna stała się automatyzacja przypadków testowych REST API wraz z przypadkami testowymi interfejsu użytkownika.
  • BDD ma format języka naturalnego opisujący cechę lub część cechy z reprezentatywnymi przykładami oczekiwanych wyników
  • Struktura Behave identyfikuje funkcję Step poprzez dopasowanie dekoratorów do predykatu pliku funkcji
  • Przykłady ram testowania BDD: 1) Cucumber 2) SpecFlow 3) Quantum 4) JBehave 5) Kodowanie