Automating your API tests using Python and Pytest

Alicia Marianne - Nov 12 '23 - - Dev Community

Did you ever thought how you can tests your APIs using python? In the article we will learn how we can test our APIs using Python and the pytest framework.
For this tutorial you need to have the python installed, you can download it here


Summary:


What is Python and Pytest Framework

Python is a high-level, general-purpose programming language known for its simplicity and readability. It was created by Guido van Rossum and first released in 1991. Python is designed to be easy to learn and has a clean and concise syntax, which makes it a popular choice for both beginners and experienced programmers.

The pytest framework makes it easy to write small, readable tests, and can scale to support complex functional testing for applications and libraries.


Configuration of our Project

Creation of virtual environment with python

Before we start creating, let's understand what is an virtual environment on python.
A virtual environment in Python is a self-contained directory or folder that allows you to create and manage isolated Python environments for your projects. With environments you can easy manage your dependencies, avoid conflicts with different versions of python.

A virtual environment is (amongst other things):

  • Used to contain a specific Python interpreter and software libraries and binaries which are needed to support a project (library or application). These are by default isolated from software in other virtual environments and Python interpreters and libraries installed in the operating system.
  • Contained in a directory, conventionally either named venv or .venv in the project directory, or under a container directory for lots of virtual environments, such as ~/.virtualenvs.
  • Not checked into source control systems such as Git.
  • Considered as disposable – it should be simple to delete and recreate it from scratch. You don’t place any project code in the environment
  • Not considered as movable or copyable – you just recreate the same environment in the target location.

You can read more about environments on python here.

Windows

First, create a folder for your project, after that, open your cmd and navigate to this folder using the command cd:



 cd tests_with_python


Enter fullscreen mode Exit fullscreen mode

If you don't know where your folder is, you can run the command ls, you will see the list of the folders and you can navigate through them. Inside of our project folder, run the follow command:



 python -m venv name_of_environment


Enter fullscreen mode Exit fullscreen mode

The name of your environment can be anyone, just remember that python is case sensitive, take a look at PEP 8 Style Guide to learn more about Python convention.

To activate our environment, we use the command:



name_of_environment\Scripts\Activate


Enter fullscreen mode Exit fullscreen mode

If everything is correct, your environment will be activated and on the cmd you will see like this:



(name_of_environment) C:\User\tests 


Enter fullscreen mode Exit fullscreen mode

To disable your environment just run:



deactivate


Enter fullscreen mode Exit fullscreen mode

Linux or MacOS

Create a folder for your project, after that, open your cmd and navigate to this folder using the command cd:



 cd tests_with_python


Enter fullscreen mode Exit fullscreen mode

To activate our environment, we use the command:



source name_of_environment/bin/activate


Enter fullscreen mode Exit fullscreen mode

If everything is correct, your environment will be activated and on the cmd you will see like this:



(name_of_environment) your_user_name tests %


Enter fullscreen mode Exit fullscreen mode

To disable your environment just run:



deactivate


Enter fullscreen mode Exit fullscreen mode

Setup of dependencies for the tests

As we're going to test APIs, we need to install dependencies to help us during our tests, first we will install the requestslibrary to help us to make the requests:
PS: Make sure that your environment is activated before run this command



pip install requests


Enter fullscreen mode Exit fullscreen mode

And to make our tests, we will install the pytests framework:



pip install pytest


Enter fullscreen mode Exit fullscreen mode

Creating our first tests

Definition of the API that will be tested

For this tutorial, we'll use the Nasa API that return a list of asteroids: Asteroids - NeoWs and we will test the endpoint that Retrieve a list of Asteroids based on their closest approach date to Earth.

About the API:

  • Base URL: https://api.nasa.gov/neo/rest/v1/feed
  • Query parameters:
Parameter Type Default Description
start_date YYYY-MM-DD none Starting date for asteroid search
end_date YYYY-MM-DD 7 days after start_date Ending date for asteroid search
api_key string DEMO_KEY api.nasa.gov key for expanded usage

For this tutorial, we will focus on three types of tests:

  • Contract: If the API is able to validate the query parameters that are sent
  • Status: If the status codes are correct
  • Authentication: Even this API doesn't requires the token, we can do tests with this

Our Scenarios:

Method Test Expected Result
GET Search with success - Return a status code 200
The body response contains the list of asteroids
GET Search without any query parameter - Return a status code 403
GET Search with start date only - Return a status code 200
The body response contain the list of asteroid
GET Search with end date only - Return a status code 200
The body response contain the list of asteroid
GET Search in an valid range of dates - Return a status code 200
- The body response contain all fields non empty
GET Search when start date is bigger than end date - Return a status code 400
GET Search with invalid API Token - Return a status code 403
The body response contain the list of asteroid

Creating our test

First, we will create a file called tests.py , at this file we will write our tests. To help us to use good practices and write a good automated test, let's use TDD(Test-Driven Development) technique.

This technique consists in:

  • RED - make a test that fail
  • GREEN - make this test pass
  • Refactor - Refactoring what was done, removing duplication

And to write a good suite of test, we will use the 3A technique:

  • Arrange: prepare the context.
  • Act: perform the action we want to demonstrate.
  • Assert: show that the outcome we expected actually occurred.

Starting with red and using 3A technique, we will write the first test Search asteroids with success:



import pytest

def test_search_asteroids_with_sucess():
    # Arrange:
    api_key = "DEMO_KEY"
    #Act:
    response = make_request(api_key)
    #Assertion:
    assert response.status_code == 200  # Validation of status code  
    data = response.json()  
    # Assertion of body response content:  
    assert len(data) > 0  
    assert data["element_count"] > 0


Enter fullscreen mode Exit fullscreen mode
  • Arrange: We create an variable to insert the api_key, in this step, you can insert any data that will be necessary to execute your test. Normally, at this step we create mock data.
  • Act: In this step we called the method responsible to make the request
  • Assertion: We validate the response

The name of the method or class should starts with test

To run our test, at command prompt, run:



pytest test.py


Enter fullscreen mode Exit fullscreen mode

We will receive an error because we didn't created our method to do the request:



test.py F                                                                                                                                      [100%]

====================================================================== FAILURES ======================================================================
_________________________________________________________ test_search_asteroids_with_sucess __________________________________________________________

    def test_search_asteroids_with_sucess():
>       response = make_request()
E       NameError: name 'make_request' is not defined

test.py:5: NameError
============================================================== short test summary info ===============================================================
FAILED test.py::test_search_asteroids_with_sucess - NameError: name 'make_request' is not defined
================================================================= 1 failed in 0.01s ==================================================================


Enter fullscreen mode Exit fullscreen mode

Now, let's create our method to do the request:



import requests

def make_request(api_key):
    base_url = "https://api.nasa.gov/neo/rest/v1/feed/"
    response = requests.get(f'{base_url}?api_key={api_key}')
    return response


Enter fullscreen mode Exit fullscreen mode

Now, running again our test:



================================================================ test session starts =================================================================
platform darwin -- Python 3.11.5, pytest-7.4.3, pluggy-1.3.0
rootdir: /Users/Documents/tests_python
collected 1 item                                                                                                                                     

test.py .                                                                                                                                      [100%]

================================================================= 1 passed in 20.22s =================================================================


Enter fullscreen mode Exit fullscreen mode

Refactoring our tests

Now that we already now how we create a test using pytest and how create a request, we can write the other tests and starting refactor the tests. The first refactor that we will do is to remove our request method from our test file. We will create a new file called make_requests.py that will contain our requests, and we will move the request that we did to this file:



import requests

def make_request(api_key):
    base_url = "https://api.nasa.gov/neo/rest/v1/feed/"
    response = requests.get(f'{base_url}?api_key={api_key}')
    return response


Enter fullscreen mode Exit fullscreen mode

Now, we need to think in an way to re-use this method for our other tests, cause we need to pass different parameters for different tests. There's a lot of ways that we can do it, for this tutorial, we will change the name of the parameter from api_key to query_parameters. We will do this to allow our method be more flexible and we can pass the parameters once for the tests:



import requests

def make_request(query_parameters):
    base_url = "https://api.nasa.gov/neo/rest/v1/feed/"
    response = requests.get(f'{base_url}?{query_parameters}')
    return response


Enter fullscreen mode Exit fullscreen mode

After that, we need to change our test file. We will import this method that we created:



from make_requests import make_request


Enter fullscreen mode Exit fullscreen mode

To have our tests organized in a better way, and following the recommendation of pytest documentation, we'll move our tests to a class TestClass:

Running our tests again:



============================= test session starts ==============================
collecting ... collected 7 items

test.py::TestClass::test_search_asteroids_with_sucess 
test.py::TestClass::test_search_asteroids_with_query_parameters_empty 
test.py::TestClass::test_search_asteroids_with_start_date 
test.py::TestClass::test_search_asteroids_with_end_date 
test.py::TestClass::test_search_asteroids_in_valid_range 
test.py::TestClass::test_search_asteroids_in_invalid_range 
test.py::TestClass::test_search_asteroids_in_invalid_token 

============================== 7 passed in 5.85s ===============================
PASSED             [ 14%]PASSED [ 28%]PASSED         [ 42%]PASSED           [ 57%]PASSED          [ 71%]PASSED        [ 85%]PASSED        [100%]
Process finished with exit code 0


Enter fullscreen mode Exit fullscreen mode

Generating html report result

To have a better visualization of your tests results, we can use the pytest-html-reporter library to generate an report html, to do it, first we need to install the package:



pip install pytest-html


Enter fullscreen mode Exit fullscreen mode

To generate the report, when running the tests, add:



pytest test.py --html-report=./report/report.html 


Enter fullscreen mode Exit fullscreen mode

Will be generated one file .html with the results of the tests, like this:

report_example

Conclusion

This article is a tutorial of how you can start to write your automated tests for an API using python and pytest framework and how generate one report html.
You can access the project used in this tutorial here.
I hope this content will be useful for you.

If you have any questions, feel free to reach out to me! 

Bisous, à la semaine prochaine 💅🏼

. . . . . . . . .