Behavior-Driven Development (BDD) Testando uma API REST com Behave

O que é o teste de BDD?

Teste de BDD (desenvolvimento orientado por comportamento) é uma técnica de desenvolvimento ágil de software e é uma extensão do TDD, ou seja, Test Driven Development. No BDD, os casos de teste são escritos em uma linguagem natural que até mesmo os não programadores podem ler.

Neste tutorial do BDD, veremos o Teste BDD da API REST com Behave e Python

Como funciona o teste BDD?

Considere que você foi designado para criar um módulo de transferência de fundos em um aplicativo Net Banking.

Existem várias maneiras de testá-lo

  1. A transferência de fundos deve ocorrer se houver saldo suficiente na conta de origem
  2. A transferência de fundos deve ocorrer se os detalhes do a / c de destino estiverem corretos
  3. A transferência de fundos deve ocorrer se a senha da transação / código rsa / autenticação de segurança para a transação inserida pelo usuário estiver correta
  4. A transferência de fundos deve ocorrer mesmo que seja feriado bancário
  5. A transferência de fundos deve ocorrer em uma data futura, conforme definido pelo titular da conta

O cenário de teste torna-se mais elaborado e complexo à medida que consideramos recursos adicionais, como a quantia de transferência X por um intervalo de Y dias / meses, interromper a transferência de agendamento quando a quantia total atinge Z e assim por diante

A tendência geral dos desenvolvedores é desenvolver recursos e escrever código de teste posteriormente. Como, evidente no caso acima, Caso de teste o desenvolvimento para esse caso é complexo e o desenvolvedor adiará o teste até o lançamento, momento em que ele fará um teste rápido, mas ineficaz.

Para superar esse problema (Behavior Driven Development), o BDD foi concebido. Isso torna todo o processo de teste fácil para um desenvolvedor

No BDD, tudo o que você escrever deve entrar Dado-quando-então degraus. Vamos considerar o mesmo exemplo acima no BDD

Dado que um módulo de transferência de fundos no aplicativo de net banking foi desenvolvido e estou acessando-o com a autenticação adequada

  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

Não é fácil escrever, ler e entender? Ele cobre todos os casos de teste possíveis para o módulo de transferência de fundos e pode ser facilmente modificado para acomodar mais. Além disso, é mais como escrever documentação para o módulo de transferência de fundos.

O que é o teste REST API?

Como o REST se tornou um estilo bastante popular para construir APIs hoje em dia, tornou-se igualmente importante automatizar os casos de teste da API REST junto com os casos de teste da IU. Então, basicamente, esses testes de API REST envolvem o teste de ações CRUD (Criar-Ler-Atualizar-Excluir) com os métodos POST, GET, PUT e DELETE respectivamente.

O que é Behave?

Behave é uma das estruturas de teste Python BDD populares.

Vamos ver como funciona o Behave:

Os arquivos de recursos são escritos por seu analista de negócios / patrocinador / quem quer que tenha seus cenários de comportamento. Ele tem um formato de linguagem natural que descreve um recurso ou parte de um recurso com exemplos representativos dos resultados esperados

Essas etapas do cenário são mapeadas com implementações de etapas escritas em Python

E, opcionalmente, existem alguns controles ambientais (código para executar antes e depois das etapas, cenários, recursos ou toda a partida de tiro).

Vamos começar com a configuração de nossa estrutura de teste de automação com Behave:

Configurando a estrutura de teste Behave no Windows:

Instalação:

Configuração do projeto:

  • Crie um novo projeto
  • Crie a seguinte estrutura de diretório:

Arquivos de recursos:

Então, vamos construir nosso arquivo de recursos Sample_REST_API_Testing.feature tendo o recurso de executar operações CRUD no serviço 'posts'.

Em nosso exemplo, usei http://jsonplaceholder.typicode.com/ posta serviço REST de amostra.

Cenário POST de exemplo:

 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 

Da mesma forma, você pode escrever os cenários restantes da seguinte maneira:

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

Implementação de etapas

Agora, para o recurso Steps usado nos cenários acima, você pode escrever implementações em arquivos Python no diretório 'steps'.

A estrutura Behave identifica a função Step por decoradores que combinam com o predicado do arquivo de feições. Por exemplo, o predicado dado no arquivo de feições Cenário procura a função de etapa com o decorador 'fornecido'. Correspondência semelhante acontece para Quando e Então. Mas no caso de 'Mas,' 'E,' a função Etapa leva o decorador da mesma forma que a etapa anterior. Por exemplo, se 'E' vier para Dado, o decorador de função de etapa correspondente é @dado.

Por exemplo, quando a etapa para POST pode ser implementada da seguinte forma:

 @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 

Da mesma forma, a implementação de outras etapas no arquivo python da etapa terá a seguinte aparência:

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 

Executando os testes:

Agora, terminamos nossa parte de desenvolvimento de script de teste, então vamos executar nossos testes:

Execute o seguinte comando no prompt de comando para executar nosso arquivo de recurso

C: Programs Python Python37> comportar-se -f bonito C: \ features feature_files_folder Sample_REST_API_Testing.feature

Isso exibirá os resultados da execução do teste da seguinte forma:

Exibição de relatório no console

Vamos ver mais uma coisa legal aqui.

Como os usuários sempre preferem ver os resultados dos testes em um formato mais legível e apresentável, vamos ter relatórios em formato HTML com a ajuda do Allure.

Relatórios

Primeiro, você precisa instalar o formatador Allure Behave [ https://docs.qameta.io/allure/ ]:

E agora execute o seguinte comando:

Para relatórios

> comporte-se -f json -o Sample_REST_API_Testing.feature

> fascinar servir

Isso irá gerar seu relatório de resultados de teste no formato apresentável e informativo como este:

Relatório de teste em formato HTML

Relatório de teste exibindo o resultado do cenário individual

Resumo:

  • BDD é o desenvolvimento orientado por comportamento. É uma das técnicas de desenvolvimento ágil de software.
  • REST se tornou um estilo bastante popular para a construção de APIs hoje em dia, tornou-se igualmente importante automatizar casos de teste de API REST junto com casos de teste de IU.
  • O BDD tem um formato de linguagem natural que descreve um recurso ou parte de um recurso com exemplos representativos dos resultados esperados
  • O framework Behave identifica a função Step por decoradores que combinam com o predicado do arquivo de feição