Τι είναι η Δοκιμή BDD; Πλαίσιο Ανάπτυξης με γνώμονα τη συμπεριφορά
⚡ Έξυπνη Σύνοψη
Η δοκιμή BDD περιγράφει τη συμπεριφορά της εφαρμογής σε απλή γλώσσα Given-When-Then, έτσι ώστε οι αναλυτές, οι προγραμματιστές και οι δοκιμαστές να μοιράζονται μία μόνο προδιαγραφή. Αυτή η αναλυτική παρουσίαση εφαρμόζει αυτήν την προσέγγιση στις δοκιμές REST API με το Behave, το Python πλαίσιο, που καλύπτει την εγκατάσταση, τα αρχεία χαρακτηριστικών, τις υλοποιήσεις βημάτων, την εκτέλεση και την αναφορά.

Τι είναι το BDD (Behavior Driven Development) Testing;
Δοκιμή BDD (Behavior-driven development). είναι μια τεχνική ευέλικτης ανάπτυξης λογισμικού και αποτελεί επέκταση του TDD, δηλαδή της ανάπτυξης με γνώμονα τις δοκιμές (Test Driven Development). Στο BDD, οι δοκιμαστικές περιπτώσεις γράφονται σε φυσική γλώσσα που μπορούν να διαβάσουν ακόμη και μη προγραμματιστές.
Πώς λειτουργεί το BDD Testing;
Ας υποθέσουμε ότι σας έχει ανατεθεί η δημιουργία μιας ενότητας Μεταφοράς Χρημάτων σε μια εφαρμογή Net Banking.
Υπάρχουν πολλοί τρόποι για να το δοκιμάσετε:
- Η μεταφορά χρημάτων θα πρέπει να πραγματοποιείται εάν υπάρχει επαρκές υπόλοιπο στον αρχικό λογαριασμό
- Η μεταφορά χρημάτων θα πρέπει να πραγματοποιείται εάν τα στοιχεία κλιματισμού προορισμού είναι σωστά
- Η μεταφορά χρημάτων θα πρέπει να πραγματοποιηθεί εάν ο κωδικός πρόσβασης συναλλαγής / ο κωδικός RSA / ο έλεγχος ταυτότητας ασφαλείας που εισήγαγε ο χρήστης είναι σωστοί.
- Η μεταφορά χρημάτων θα πρέπει να πραγματοποιείται ακόμη και αν είναι αργία
- Η μεταφορά κεφαλαίων θα πρέπει να πραγματοποιείται σε μελλοντική ημερομηνία όπως ορίζεται από τον κάτοχο του λογαριασμού
The Σενάριο δοκιμής γίνεται πιο περίπλοκο και περίπλοκο καθώς εξετάζουμε πρόσθετα χαρακτηριστικά όπως η μεταφορά ποσού Χ για ένα διάστημα Y ημερών ή μηνών, η διακοπήping μια προγραμματισμένη μεταφορά όταν το σύνολο φτάσει το Z, και ούτω καθεξής.
Η γενική τάση των προγραμματιστών είναι να αναπτύσσουν λειτουργίες και να γράφουν κώδικα δοκιμών αργότερα. Όπως είναι εμφανές στην παραπάνω περίπτωση, Δοκιμαστική θήκη η ανάπτυξη εδώ είναι περίπλοκη, επομένως ο προγραμματιστής θα αναβάλει Δοκιμές μέχρι την κυκλοφορία του, οπότε και διεξάγονται γρήγορες αλλά αναποτελεσματικές δοκιμές.
Για να ξεπεραστεί αυτό το πρόβλημα, σχεδιάστηκε η Ανάπτυξη με γνώμονα τη συμπεριφορά (BDD). Κάνει ολόκληρη τη διαδικασία δοκιμών ευκολότερη για έναν προγραμματιστή.
Στο BDD, ό,τι και να γράψεις πρέπει να μπαίνει μέσα Δοσμένο-Πότε-Τότε βήματα. Ας εξετάσουμε το ίδιο παράδειγμα παραπάνω στο BDD:
Given that a fund transfer module in net banking application has been developed And I am accessing it with proper authentication When I 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
Αυτή η φόρμα είναι εύκολη στη σύνταξη, την ανάγνωση και την κατανόηση. Καλύπτει κάθε πιθανή δοκιμαστική περίπτωση για την ενότητα μεταφοράς κεφαλαίων και μπορεί να τροποποιηθεί γρήγορα για να φιλοξενήσει περισσότερα. Διαβάζεται επίσης σαν ζωντανή τεκμηρίωση για την ενότητα. Επειδή το BDD προέκυψε από το TDD, η διαφορά μεταξύ των δύο αξίζει να διευθετηθεί πριν προχωρήσουμε στα εργαλεία.
BDD έναντι TDD: Βασικές διαφορές
Και οι δύο πρακτικές δίνουν προτεραιότητα στις δοκιμές και συντομεύουν τους βρόχους ανατροφοδότησης. Διαφέρουν ως προς το ποιος γράφει τις δοκιμές, τη γλώσσα που χρησιμοποιούν αυτές οι δοκιμές και ποιο επίπεδο της εφαρμογής περιγράφουν.
| Άποψη | TDD (Ανάπτυξη βάσει δοκιμών) | BDD (Ανάπτυξη με γνώμονα τη συμπεριφορά) |
|---|---|---|
| Συγκέντρωση | Πώς λειτουργεί εσωτερικά μια μονάδα κώδικα | Πώς συμπεριφέρεται το σύστημα από την οπτική γωνία του χρήστη |
| Γλώσσα | Ισχυρισμοί γλώσσας προγραμματισμού | Σενάρια φυσικής γλώσσας με δεδομένα-πότε-τότε |
| Κύριος συγγραφέας | Προγραμματιστής | Αναλυτής επιχειρήσεων, κάτοχος προϊόντος, δοκιμαστής και προγραμματιστής μαζί |
| Readable από μη προγραμματιστές | Οχι | Ναι |
| Τυπικό πεδίο εφαρμογής | Επίπεδο μονάδας | Χαρακτηριστικό, API και επίπεδο αποδοχής |
| Κοινά εργαλεία | JUnit, pytest, NUnit | Συμπεριφέρομαι, Cucumber, SpecFlow, JBehave |
Τα δύο είναι συμπληρωματικά και όχι ανταγωνιστικά. Οι ομάδες συνήθως διατηρούν TDD για σχεδιασμό σε επίπεδο μονάδας και προσθέστε σενάρια BDD στην κορυφή για να περιγράψετε τη συμπεριφορά που στην πραγματικότητα εγκρίνουν τα ενδιαφερόμενα μέρη. Δεδομένου ότι τα τελικά σημεία REST βρίσκονται ακριβώς σε αυτό το επίπεδο αποδοχής, είναι φυσικά κατάλληλα για BDD.
Τι είναι το REST API Testing;
Καθώς το REST έχει γίνει ένα δημοφιλές στυλ για τη δημιουργία API, η αυτοματοποίηση των περιπτώσεων δοκιμών REST API παράλληλα με τις περιπτώσεις δοκιμών UI έχει γίνει εξίσου σημαντική. Δοκιμή API περιλαμβάνει τον έλεγχο των ενεργειών CRUD (Δημιουργία-Ανάγνωση-Ενημέρωση-Διαγραφή) με τις μεθόδους POST, GET, PUT και DELETE αντίστοιχα.
Τι είναι το Behave;
Το Behive είναι ένα από τα δημοφιλή Python Πλαίσια δοκιμών BDD. Δείτε πώς λειτουργεί το Behave:
- Τα αρχεία χαρακτηριστικών γράφονται από τον Επιχειρηματικό Αναλυτή, τον Χορηγό σας ή οποιονδήποτε άλλον κατέχει τα σενάρια συμπεριφοράς. Ένα αρχείο χαρακτηριστικών χρησιμοποιεί μια μορφή φυσικής γλώσσας που περιγράφει ένα χαρακτηριστικό ή μέρος ενός χαρακτηριστικού, με αντιπροσωπευτικά παραδείγματα αναμενόμενων αποτελεσμάτων.
- Αυτά τα βήματα σεναρίου αντιστοιχίζονται σε υλοποιήσεις βημάτων που είναι γραμμένες σε Python.
- Προαιρετικά, οι περιβαλλοντικοί έλεγχοι εκτελούν κώδικα πριν και μετά από βήματα, σενάρια, λειτουργίες ή ολόκληρη την εκτέλεση.
Με τους ρόλους κάθε αρχείου σαφείς, το framework μπορεί τώρα να εγκατασταθεί.
Ρύθμιση του πλαισίου δοκιμών BDD Behave on Windows
Εγκατάσταση:
- Κατεβάστε και εγκαταστήστε Python 3 από https://www.python.org/
- Εκτελέστε την ακόλουθη εντολή στη γραμμή εντολών για να εγκαταστήσετε το Behave
pip install behave- SDI: PyCharm Η Έκδοση Κοινότητας χρησιμοποιείται εδώ — https://www.jetbrains.com/pycharm/download/
Ρύθμιση έργου:
- Δημιουργήστε ένα νέο έργο
- Δημιουργήστε την ακόλουθη δομή καταλόγου
Το παραπάνω στιγμιότυπο οθόνης δείχνει τη διάταξη που αναμένει η Behave: a χαρακτηριστικά κατάλογο που περιέχει τα αρχεία χαρακτηριστικών και έναν ένθετο βήματα κατάλογος που περιέχει το Python υλοποιήσεις. Η λειτουργία Behavior discovers (συμπεριφέρεται) κάνει τις ανακαλύψεις και των δύο με το όνομά τους, επομένως τα ονόματα των φακέλων πρέπει να ταιριάζουν ακριβώς.
Αρχεία δυνατοτήτων:
Τώρα ας δημιουργήσουμε το αρχείο χαρακτηριστικών Sample_REST_API_Testing.feature, με το χαρακτηριστικό να είναι οι λειτουργίες CRUD στην υπηρεσία «αναρτήσεις».
Αυτό το παράδειγμα χρησιμοποιεί το https://jsonplaceholder.typicode.com/ Δημοσιεύει ένα δείγμα υπηρεσίας REST, ένα δωρεάν ψεύτικο API που δέχεται αιτήματα εγγραφής και επιστρέφει ρεαλιστικές απαντήσεις χωρίς επίμονες αλλαγές.
Παράδειγμα σεναρίου POST
Scenario: POST post example -> creating a new post item using the 'posts' service Given I set post posts API endpoint -> prerequisite: sets the URL of the posts service When I set HEADER param request content type as "application/json" And set request body And send POST HTTP request -> the actual test step Then I receive valid HTTP response code 201 And Response body "POST" is non-empty -> verification of the response body
Ομοίως, μπορείτε να γράψετε τα υπόλοιπα σενάρια ως εξής:
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"
Βήματα Υλοποίηση
Τώρα, για τα βήματα χαρακτηριστικών που χρησιμοποιούνται στα παραπάνω σενάρια, μπορείτε να γράψετε υλοποιήσεις σε Python αρχεία μέσα στον κατάλογο "βήματα".
Το πλαίσιο Behave προσδιορίζει τη συνάρτηση βημάτων αντιστοιχίζοντας τους διακοσμητές με το κατηγόρημα του αρχείου χαρακτηριστικών. Για παράδειγμα, ένα Δεδομένου κατηγόρημα σε ένα σενάριο αρχείου χαρακτηριστικών αναζητά μια βηματική συνάρτηση που φέρει το @given διακοσμητής. Η ίδια αντιστοίχιση συμβαίνει και για Κατά τη και ΤότεΣτην περίπτωση των «Αλλά» και «Και», η συνάρτηση βήματος λαμβάνει τον ίδιο διακοσμητή με το προηγούμενο βήμα της. Για παράδειγμα, αν το «Και» ακολουθεί ένα δεδομένο, ο αντίστοιχος διακοσμητής συνάρτησης βήματος είναι @given.
Για παράδειγμα, το βήμα When για το POST μπορεί να υλοποιηθεί ως εξής. Σημειώστε πώς "application/json" μεταβιβάζεται από το αρχείο χαρακτηριστικών στο placeholder με αγκύλες — αυτό ονομάζεται παραμετροποίηση.
# Decorator: the braced name captures a value from the feature file @when(u'I Set HEADER param request content type as "{header_content_type}"') def step_impl(context, header_content_type): # Step implementation: set the content type on the request header request_headers['Content-Type'] = header_content_type
Ομοίως, η εφαρμογή των άλλων βημάτων στο βήμα Python το αρχείο θα μοιάζει με αυτό:
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 = 'https://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_content_type}"') def step_impl(context, header_content_type): request_headers['Content-Type'] = header_content_type # "And" or "But" steps are renamed by behave to match their preceding step @when(u'Set request Body') def step_impl(context): request_bodies['POST'] = {"title": "foo", "body": "bar", "userId": "1"} @when(u'Send POST HTTP request') def step_impl(context): # send the request and save the response object response = requests.post(url=api_endpoints['POST_URL'], json=request_bodies['POST'], headers=request_headers) response_texts['POST'] = response.text print("post response :" + response.text) response_codes['POST'] = response.status_code @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'] == 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']) @when(u'Send GET HTTP request') def step_impl(context): response = requests.get(url=api_endpoints['GET_URL'], headers=request_headers) response_texts['GET'] = response.text response_codes['GET'] = response.status_code @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] == 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): response = requests.put(url=api_endpoints['PUT_URL'], json=request_bodies['PUT'], headers=request_headers) response_texts['PUT'] = response.text print("update response :" + response.text) response_codes['PUT'] = response.status_code # 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): response = requests.delete(url=api_endpoints['DELETE_URL']) response_texts['DELETE'] = response.text print("DELETE response :" + response.text) response_codes['DELETE'] = response.status_code # END DELETE
⚠️ Σημείωση: Σύγκριση κωδικών κατάστασης με == αντί is έχει σημασία. Το is Ο τελεστής ελέγχει την ταυτότητα του αντικειμένου, όχι την ισότητα, και Python 3.8 και νεότερες εκδόσεις αυξάνουν ένα Προειδοποίηση σύνταξης: «είναι» με κυριολεκτική για αυτό το μοτίβο. Οποιοσδήποτε ισχυρισμός γραμμένος ως assert code is 201 θα πρέπει να ξαναγραφεί ως assert code == 201.
Εκτέλεση των δοκιμών
Η ανάπτυξη του σεναρίου δοκιμής ολοκληρώθηκε, επομένως ας εκτελέσουμε τις δοκιμές. Εκτελέστε την ακόλουθη εντολή στη γραμμή εντολών για να εκτελέσετε το αρχείο χαρακτηριστικών:
:: Run a single feature file with the pretty formatter behave -f pretty features\feature_files_folder\Sample_REST_API_Testing.feature :: Run every feature in the project behave
Αυτό εμφανίζει τα αποτελέσματα εκτέλεσης της δοκιμής ως εξής:
Εμφάνιση αναφοράς στην κονσόλα
Η έξοδος της κονσόλας είναι βολική κατά την ανάπτυξη, αλλά οι ενδιαφερόμενοι συνήθως προτιμούν μια ευανάγνωστη αναφορά, την οποία παρέχει το Allure.
Εκθέσεις
Αρχικά, εγκαταστήστε το πρόγραμμα μορφοποίησης Allure Behave και το εργαλείο γραμμής εντολών Allure. Το πρόγραμμα μορφοποίησης είναι ένα Python πακέτο; το εργαλείο γραμμής εντολών είναι ένα ξεχωριστό αρχείο λήψης που περιγράφεται στο Τεκμηρίωση της Έκθεσης Allure.
:: 1. Install the formatter pip install allure-behave :: 2. Run the tests and write raw results to a folder behave -f allure_behave.formatter:AllureFormatter -o reports/allure-results features/ :: 3. Render and open the HTML report allure serve reports/allure-results
Αυτό δημιουργεί την αναφορά αποτελεσμάτων δοκιμών σε μια ευπαρουσίαστη και ενημερωτική μορφή όπως αυτή:
Έκθεση δοκιμής σε μορφή HTML
Έκθεση δοκιμής που εμφανίζει μεμονωμένο αποτέλεσμα σεναρίου
Μια λειτουργική σουίτα είναι χρήσιμη μόνο εάν παραμένει ευανάγνωστη καθώς το API αναπτύσσεται, και εκεί αποδίδει η πειθαρχία στα αρχεία χαρακτηριστικών.
καλυτερα Practices for Writing Behave Feature Files
Μια σουίτα Behave υποβαθμίζεται γρήγορα όταν τα σενάρια περιγράφουν κλικ και ωφέλιμα φορτία αντί για συμπεριφορά. Οι παρακάτω πρακτικές διατηρούν τα αρχεία χαρακτηριστικών αναγνώσιμα για τους επιχειρηματικούς ενδιαφερόμενους, διατηρώντας παράλληλα...ping ο Python στρώμα που μπορεί να συντηρηθεί από μηχανικούς.
- Περιγράψτε τη συμπεριφορά, όχι την υλοποίηση. Γράψτε «Δεδομένου ότι ένας πελάτης έχει επαρκές υπόλοιπο», όχι «Δεδομένου ότι η στήλη υπολοίπου ισούται με 500». Το αρχείο χαρακτηριστικών αναφέρει τι κάνει το σύστημα. Το αρχείο βημάτων αναφέρει πώς ελέγχεται.
- Διατηρήστε μία συμπεριφορά ανά σενάριο. Ένα σενάριο που απαιτεί έναν κωδικό κατάστασης, ένα σώμα απόκρισης και μια γραμμή βάσης δεδομένων αποτελείται στην πραγματικότητα από τρία σενάρια. Ο διαχωρισμός τους κάνει τις αποτυχίες να υποδεικνύουν άμεσα την αιτία.
- Μετακίνηση κοινόχρηστης ρύθμισης στο φόντο. Το παραπάνω παράδειγμα χρησιμοποιεί
Background: Given I set sample REST API urlέτσι ώστε κάθε σενάριο να κληρονομεί τη βάση URL χωρίς να το επαναλάβει. - Παραμετροποιήστε αντί να αντιγράφετε. Υποδοχείς με αγκύλες όπως
"{request_name}"Αφήστε τη συνάρτηση ενός βήματος να εξυπηρετεί ισχυρισμούς GET, PUT και DELETE, γι' αυτό και το παράδειγμα χρειάζεται πολύ λιγότερους ορισμούς βημάτων από τα σενάρια. - Χρησιμοποιήστε το Scenario Outline για παραλλαγές δεδομένων. Όταν η ίδια συμπεριφορά πρέπει να αποδειχθεί για περισσότερες εισόδους, ένα
Examples:Ο πίνακας είναι πιο σαφής από τα αντιγραμμένα σενάρια. - Αποφύγετε τις εξαρτήσεις μεταξύ σεναρίων. Η συνάρτηση Behave δεν εγγυάται ότι ένα σενάριο POST θα εκτελεστεί πριν από ένα σενάριο GET σε κάθε διαμόρφωση. Κάθε σενάριο θα πρέπει να δημιουργεί την κατάσταση που χρειάζεται.
- Αντικαταστήστε τις καθολικές τιμές σε επίπεδο ενότητας με το περιβάλλον. Το παράδειγμα αποθηκεύει τα τελικά σημεία και τις απαντήσεις σε λεξικά μονάδων για συντομία. Στις σουίτες παραγωγής, αποθηκεύστε τα στο Behave's
contextαντικείμενο, έτσι ώστε η κατάσταση να επαναφέρεται καθαρά μεταξύ των σεναρίων. - Σενάρια ετικετών για επιλεκτικές εκτελέσεις. Ετικέτες όπως
@smokeor@regressionεπιτρέπουνbehave --tags=@smoke, το οποίο διατηρεί την ανατροφοδότηση του αγωγού γρήγορη.
Η εφαρμογή αυτών των συνηθειών από το πρώτο αρχείο χαρακτηριστικών διατηρεί μια σουίτα BDD πολύτιμη πολύ πέρα από τα αρχικά παραδείγματα CRUD. Οι ομάδες που επεκτείνουν περαιτέρω αυτήν την προσέγγιση συχνά τη συνδυάζουν με Cucumber για έργα JVM ή Postman για διερευνητικούς ελέγχους API.






