¿Qué es BDD Testing? Marco de desarrollo basado en el comportamiento.
⚡ Resumen inteligente
Las pruebas BDD describen el comportamiento de la aplicación en un lenguaje simple de Dado-Cuando-Entonces para que analistas, desarrolladores y evaluadores compartan una especificación. Este tutorial aplica ese enfoque a las pruebas de API REST con Behave, la Python marco de trabajo que abarca la configuración, los archivos de características, las implementaciones de pasos, la ejecución y la generación de informes.

¿Qué son las pruebas BDD (desarrollo impulsado por el comportamiento)?
Pruebas BDD (desarrollo impulsado por el comportamiento) BDD es una técnica de desarrollo de software ágil y una extensión de TDD, es decir, Desarrollo Dirigido por Pruebas. En BDD, los casos de prueba se escriben en un lenguaje natural que incluso personas sin conocimientos de programación pueden leer.
¿Cómo funcionan las pruebas BDD?
Imagina que te han asignado la tarea de crear un módulo de transferencia de fondos en una aplicación de banca en línea.
Existen varias formas de comprobarlo:
- La transferencia de fondos se realizará si hay saldo suficiente en la cuenta de origen.
- La transferencia de fondos debe realizarse si los detalles de la cuenta de destino son correctos
- La transferencia de fondos debería realizarse si la contraseña de la transacción / el código RSA / la autenticación de seguridad ingresada por el usuario son correctos.
- La transferencia de fondos debe realizarse incluso si es día festivo bancario.
- La transferencia de fondos debe realizarse en una fecha futura establecida por el titular de la cuenta.
El Escenario de prueba se vuelve más elaborado y complejo a medida que consideramos características adicionales como transferir la cantidad X durante un intervalo de Y días o meses, detenerping una transferencia programada cuando el total alcance Z, y así sucesivamente.
La tendencia general de los desarrolladores es desarrollar las funcionalidades y escribir el código de prueba más tarde. Como se evidencia en el caso anterior, Caso de prueba El desarrollo aquí es complejo, por lo que el desarrollador lo pospondrá. Pruebas hasta su lanzamiento, momento en el que se realizan pruebas rápidas pero ineficaces.
Para solucionar este problema, se concibió el Desarrollo Dirigido por Comportamiento (BDD, por sus siglas en inglés). Este método facilita todo el proceso de pruebas para el desarrollador.
En BDD, todo lo que escriba debe ir a Dado-cuando-entonces pasos. Consideremos el mismo ejemplo anterior en 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
Este formulario es fácil de escribir, leer y comprender. Cubre todos los casos de prueba posibles para el módulo de transferencia de fondos y se puede modificar rápidamente para incluir más. Además, funciona como documentación viva del módulo. Dado que BDD surgió de TDD, conviene aclarar la diferencia entre ambos antes de pasar a las herramientas.
BDD vs TDD: Diferencias clave
Ambas prácticas se basan en el desarrollo mediante pruebas y ambas acortan los ciclos de retroalimentación. Se diferencian en quién escribe las pruebas, qué lenguaje utilizan y qué capa de la aplicación describen.
| Aspecto | TDD (Desarrollo Dirigido por Pruebas) | BDD (desarrollo impulsado por el comportamiento) |
|---|---|---|
| Enfócate | Cómo funciona internamente una unidad de código | Cómo se comporta el sistema desde la perspectiva del usuario |
| Idioma | aserciones del lenguaje de programación | Escenarios de lenguaje natural Dado-Cuando-Entonces |
| Autor principal | Developer | Analista de negocios, propietario de producto, probador y desarrollador juntos |
| Readable por personas que no son programadoras | No | Sí: |
| Alcance típico | Nivel de unidad | Funcionalidad, API y nivel de aceptación |
| Herramientas comunes | JUnit, pytest, NUnit | Comportarse, Cucumber, SpecFlow, JBehave |
Los dos son complementarios en lugar de competir. Los equipos suelen mantener TDD para el diseño a nivel de unidad y agregar escenarios BDD para describir el comportamiento que las partes interesadas aprueban. Dado que los puntos finales REST se ubican precisamente en esa capa de aceptación, son ideales para BDD.
¿Qué son las pruebas de API REST?
Dado que REST se ha convertido en un estilo popular para la creación de API, la automatización de los casos de prueba de API REST junto con los casos de prueba de interfaz de usuario se ha vuelto igualmente importante. Pruebas de API Consiste en probar las acciones CRUD (Crear-Leer-Actualizar-Eliminar) con los métodos POST, GET, PUT y DELETE respectivamente.
¿Qué es comportarse?
Comportarse es uno de los populares. Python Marcos de prueba BDD. Así es como funciona Behave:
- Los archivos de características los redacta el analista de negocio, el patrocinador o la persona responsable de los escenarios de comportamiento. Un archivo de características utiliza un formato de lenguaje natural que describe una característica, o parte de ella, con ejemplos representativos de los resultados esperados.
- Estos pasos del escenario se asignan a implementaciones de pasos escritas en Python.
- Opcionalmente, los controles ambientales ejecutan código antes y después de los pasos, escenarios, funciones o de toda la ejecución.
Una vez definidas las funciones de cada archivo, ya se puede instalar el framework.
Configuración del marco de pruebas BDD Comportarse en Windows
Instalación:
- Descarga e instala Python 3 de https://www.python.org/
- Ejecuta el siguiente comando en la línea de comandos para instalar Behave.
pip install behave- IDE: PyCharm Aquí se utiliza la edición comunitaria. https://www.jetbrains.com/pycharm/download/
Configuración del proyecto:
- Crear un nuevo proyecto
- Cree la siguiente estructura de directorios
La captura de pantalla anterior muestra el diseño que Behave espera: un Características directorio que contiene los archivos de características y un directorio anidado pasos directorio que contiene el Python implementaciones. Behave los detecta ambos por nombre, por lo que los nombres de las carpetas deben coincidir exactamente.
Archivos de características:
Ahora vamos a crear el archivo de características. Característica_muestra_REST_API_Testing., siendo la característica principal las operaciones CRUD en el servicio de 'publicaciones'.
Este ejemplo usa el https://jsonplaceholder.typicode.com/ Publica un servicio REST de ejemplo, una API simulada gratuita que acepta solicitudes de escritura y devuelve respuestas realistas sin guardar los cambios.
Ejemplo de escenario 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
De forma similar, puedes escribir los escenarios restantes de la siguiente manera:
Característica_muestra_REST_API_Testing.
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"
Implementación de pasos
Ahora, para los pasos de características utilizados en los escenarios anteriores, puede escribir implementaciones en Python archivos dentro del directorio “steps”.
El marco Behave identifica la función de paso comparando los decoradores con el predicado del archivo de características. Por ejemplo, un Dado que los El predicado en un escenario de archivo de características busca una función escalonada que contenga la @given decorador. La misma coincidencia ocurre para Cuando y EntoncesEn el caso de 'But' y 'And', la función de paso toma el mismo decorador que su paso precedente. Por ejemplo, si 'And' sigue a un Given, el decorador de la función de paso correspondiente es @given.
Por ejemplo, el paso When para POST se puede implementar de la siguiente manera. Observe cómo "application/json" se pasa desde el archivo de características al marcador de posición entre llaves; esto se llama parametrización.
# 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
De manera similar, la implementación de los demás pasos en el paso Python El archivo se verá así:
ejemplo_paso_implementación.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
⚠️ Nota: Comparación de códigos de estado con == más bien que is asuntos. El is El operador prueba la identidad del objeto, no la igualdad, y Python 3.8 y luego plantear una SyntaxWarning: “is” con un literal para ese patrón. Cualquier afirmación escrita como assert code is 201 debería reescribirse como assert code == 201.
Ejecutando las pruebas
El desarrollo del script de prueba está completo, así que procedamos a ejecutar las pruebas. Ejecute el siguiente comando en la línea de comandos para ejecutar el archivo de características:
:: 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
Esto muestra los resultados de la ejecución de la prueba de la siguiente manera:
Visualización de informes en la consola.
La salida desde la consola resulta práctica durante el desarrollo, pero las partes interesadas suelen preferir un informe legible, que es precisamente lo que ofrece Allure.
Informes
Primero, instale el formateador Allure Behave y la herramienta de línea de comandos Allure. El formateador es un Python paquete; la herramienta de línea de comandos es una descarga separada descrita en el Documentación del Informe 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
Esto genera el informe de resultados de la prueba en un formato presentable e informativo como este:
Informe de prueba en formato HTML
Informe de prueba que muestra el resultado del escenario individual
Un conjunto de herramientas funcional solo es útil si se mantiene legible a medida que crece la API, y es ahí donde la disciplina en los archivos de características da sus frutos.
Mejores prácticas para escribir archivos de características Behave
Una suite Behave se degrada rápidamente cuando los escenarios describen clics y cargas útiles en lugar de comportamiento. Las prácticas que se describen a continuación mantienen los archivos de características legibles para las partes interesadas del negocio, al tiempo que mantienenping <font dir="auto" style="vertical-align: inherit;">las </font> Python Capa mantenible para ingenieros.
- Describe el comportamiento, no la implementación. Escriba “Dado que un cliente tiene saldo suficiente”, no “Dado que la columna de saldo es igual a 500”. El archivo de características indica qué hace el sistema; el archivo de pasos indica cómo se verifica.
- Mantén un comportamiento por escenario. Un escenario que requiere un código de estado, un cuerpo de respuesta y una fila de base de datos en realidad consta de tres escenarios. Al separarlos, los fallos apuntan directamente a la causa.
- Mover la configuración compartida a segundo plano. El ejemplo anterior utiliza
Background: Given I set sample REST API urlpara que cada escenario herede la base URL sin repetirlo. - Parametrizar en lugar de duplicar. Marcadores de posición reforzados como
"{request_name}"Dejemos que una función de paso sirva para las aserciones GET, PUT y DELETE, razón por la cual el ejemplo necesita muchas menos definiciones de pasos que escenarios. - Utilice el esquema de escenarios para las variaciones de datos. Cuando se debe demostrar el mismo comportamiento para varias entradas, un
Examples:La tabla es más clara que los escenarios copiados. - Evite las dependencias entre escenarios. Behave no garantiza que un escenario POST se ejecute antes que un escenario GET en todas las configuraciones. Cada escenario debe crear el estado que necesita.
- Reemplazar las variables globales a nivel de módulo con el contexto. El ejemplo almacena los endpoints y las respuestas en diccionarios de módulos para mayor brevedad. En suites de producción, almacénelos en Behave.
contextobjeto para que el estado se restablezca limpiamente entre escenarios. - Etiquetar escenarios para ejecuciones selectivas. Etiquetas como
@smokeor@regressionpermitirbehave --tags=@smoke, lo que mantiene la retroalimentación del proceso rápida.
Aplicar estos hábitos desde el primer archivo de características mantiene la utilidad de un conjunto de BDD mucho más allá de los ejemplos CRUD iniciales. Los equipos que extienden aún más este enfoque a menudo lo combinan con Cucumber para proyectos JVM o Postman para comprobaciones exploratorias de la API.






