SoapUI
Assertions in SoapUI: Complete Tutorial
What Is an Assertion? Assertion means act of affirming or stating something. It can also be...
BDD (Behavior-driven development) Testing is a technique of agile software development and is as an extension of TDD, i.e., Test Driven Development. In BDD, test cases are written in a natural language that even non-programmers can read.
In this BDD tutorial, we are going to see BDD Testing of REST API with Behave and Python
Consider you are assigned to create Funds Transfer module in a Net Banking application.
There are multiple ways to test it
The Test Scenario become more elaborate and complex as we consider additional features like transfer amount X for an interval Y days/months , stop schedule transfer when the total amount reaches Z , and so on
The general tendency of developers is to develop features and write test code later. As, evident in above case, Test Case development for this case is complex and developer will put off Testing till release , at which point he will do quick but ineffective testing.
To overcome this issue (Behavior Driven Development) BDD was conceived. It makes the entire testing process easy for a developer
In BDD, whatever you write must go into Given-When-Then steps. Lets consider the same example above in 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
Isn't it easy to write and read and understand? It covers all possible test cases for the fund transfer module and can be easily modified to accommodate more. Also, it more like writing documentation for the fund transfer module.
As REST has become quite a popular style for building APIs nowadays, it has become equally important to automate REST API test cases along with UI test cases. So basically, these REST API testing involves testing of CRUD (Create-Read-Update-Delete) actions with methods POST, GET, PUT, and DELETE respectively.
Behave is one of the popular Python BDD test frameworks.
Let's see how does Behave function:
Feature files are written by your Business Analyst / Sponsor / whoever with your behavior scenarios in it. It has a natural language format describing a feature or part of a feature with representative examples of expected outcomes
These Scenario steps are mapped with step implementations written in Python
And optionally, there are some environmental controls (code to run before and after steps, scenarios, features or the whole shooting match).
Let's get started with the setup of our automation test framework with Behave:
So let's build our feature file Sample_REST_API_Testing.feature having feature as Performing CRUD operations on 'posts' service.
In our example, I have used http://jsonplaceholder.typicode.com/ posts sample REST Service.
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
Similarly, you can write the remaining Scenarios as follows:
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."
Now, for feature Steps used in the above scenarios, you can write implementations in Python files in the "steps" directory.
Behave framework identifies the Step function by decorators matching with feature file predicate. For Example, Given predicate in Feature file Scenario searches for step function having decorator "given." Similar matching happens for When and Then. But in the case of 'But,' 'And,' Step function takes decorator same as it's preceding step. For Example, If 'And' comes for Given, matching step function decorator is @given.
For Example, when step for POST can be implemented as follows:
@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
Similarly, the implementation of other steps in the step python file will look like this:
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
Now, we are done with our test script development part, so let's run our tests:
Execute the following command on command prompt to run our feature file
C: \Programs\Python\Python37>behave -f pretty C:\<your project path>\features\feature_files_folder\Sample_REST_API_Testing.feature
This will display test execution results as follows:
Report display on the console
Let's see one more cool thing here.
As users always prefer to see test results in a more readable and presentable format, let's have reports in HTML format with the help of Allure.
First, you need to install Allure Behave formatter [https://docs.qameta.io/allure/]:
And now execute the following command:
For reports
>behave -f json -o<path-to-your-report-folder> Sample_REST_API_Testing.feature
<allure-bin folder path>> allure serve <path-to-your-report-folder>
This will generate your test results report in the presentable and informative format like this:
Test Report in HTML Format
Test Report displaying individual Scenario result
What Is an Assertion? Assertion means act of affirming or stating something. It can also be...
Training Summary SoapUI is the market leader in API Testing Tool. You can do functional, load,...
Understanding the SOAP Protocol Before we create a SOAPUI Test case, let us understand basics...
1) Explain what is SOAP UI? SOAP UI is a free, open source cross-platform functional Testing...
What is SOAP UI? SOAP UI is the leading open source cross-platform API Testing tool SOAPUI allows...
Download PDF 1) Explain what is REST and RESTFUL? REST represents REpresentational State Transfer;...