DEV Community

Gaurav Singh
Gaurav Singh

Posted on • Originally published at automationhacks.io on

Python API test automation framework (Part 3) Adding fluent assertions using assertpy

Python and requests and header

Logos in header image sources:Python,Requests,JSON,HTTP

This is second post in a series on how to build an API framework using python.

You can read previous parts below:

An integral part of any test automation framework is how you perform assertions ✅ 🔴. You can also argue that it’s the essential bread and butter of test automation. Ever seen a test that does not assert anything? 🤔

While you can always choose what comes out of the box with your language or test framework, or even come up with your own wrappers. It’s always a good idea to not reinvent the wheel ☸️ and leverage a good assertion lib to save you some valuable implementation time.

For python, there are many options available. However I particularly like the assertpy library for its fluent assertion capabilities and the fact that it has excellent support for working with native python data structures like list, set, dict among other primitive data types.

It is heavily inspired from AssertJ library which in itself is quite popular in the Java community and used in many popular open source tools

Starting with fluent assertions

How to start with fluent assertions with assertpy, you may ask?

Like any other python module, You should start by adding it to your virtual env by using below

pipenv install assertpy

Enter fullscreen mode Exit fullscreen mode

Also, reading the exhaustive and well written Github readme is an excellent starting point as it provides you with a huge list of operations and methods that are possible with assertpy. You can learn more on assertpy/assertpy

Basic assertions

Let’s see some basic assertions for our use cases and I would leave the rest to you to explore as and when you encounter certain use cases.

It’s generally always a good idea to skim through the library’s capabilities so that your brain remembers if capability X is something that you have already seen and just that act can help you with future use case

Let’s say you want to chain multiple assertions on a particular person from the same people response that we have been looking at:

[
    {
        "fname": "Kent",
        "lname": "Brockman",
        "person_id": 2,
        "timestamp": "2020-12-01T16:50:36.843495"
    },
    {
        "fname": "Bunny",
        "lname": "Easter",
        "person_id": 3,
        "timestamp": "2020-12-01T16:50:36.843706"
    }
    ...
]

Enter fullscreen mode Exit fullscreen mode

Remember we did the check of extracting the first names from available persons and then added a check to see if Kent is contained in this:

first_names = [people['fname'] for people in response_text]
assert_that(first_names).contains('Kent')

Enter fullscreen mode Exit fullscreen mode

We can use capabilities offered by assertpy to extract a list from a list of dict objects based on a certain key and then chain multiple assertions together. The above can be effectively replaced with.

assert_that(response_content).extracting('fname').is_not_empty().contains('Gaurav')

Enter fullscreen mode Exit fullscreen mode

Observe that we are able to do multiple checks on the same object and this reads fluently like an english sentence. 🙌🏼

Also, Notice when the assertion fails, we get a friendly human readable error message like below:

AssertionError: Expected <['Kent', 'Bunny', 'Doug']> to contain item <Gaurav>, but did not.

Enter fullscreen mode Exit fullscreen mode

Replace Gaurav with Kent to see the assertion pass.

The most common operations that you might perform with the assertion library are:

is_equal_to, is_empty, contains, does_not_contain, matches

Enter fullscreen mode Exit fullscreen mode

And these among many others are easily supported by assertpy out of the box.

Printing a custom assertion message

Let’s say you want your own custom message to be printed when an assertion fails, You can easily do that use description='' keyword argument

assert_that(response.status_code, description='Person not created').is_equal_to(requests.codes.ok)

Enter fullscreen mode Exit fullscreen mode

For example, I’ve wrongly modified the expected response code from no_content to ok and assertpy gives the below readable stack trace along with our provided error message

> assert_that(response.status_code, description='Person not created').is_equal_to(requests.codes.ok)
E AssertionError: [Person not created] Expected <204> to be equal to <200>, but was not.

people_test.py:63: AssertionError

Enter fullscreen mode Exit fullscreen mode

Soft assertions

You can also do Soft assertions (i.e not stop your test on the first failure) but instead raise a single assertion error at the end, to do so, ensure that you make use of soft_assertions()function and python context manager using with clause

def test_read_all_has_kent():
   # We use requests.get() with url to make a get request
   response = requests.get(BASE_URI)
   # response from requests has many useful properties
   # we can assert on the response status code

   with soft_assertions():
       assert_that(response.status_code).is_equal_to(requests.codes.no_content) # fails
       # We can get python dict as response by using .json() method
       response_content = response.json()

       # Use assertpy's fluent assertions to extract all fnames and then see the result is non empty and has
       # Kent in it.
       assert_that(response_content).extracting('fname').is_not_empty().does_not_contain('Kent') # fails

Enter fullscreen mode Exit fullscreen mode

In the above example, we’ve deliberately modified the status code assertion and the response assertion.

Below is how it looks like once the test has run, we see both assertion messages show up.

E AssertionError: soft assertion failures:
E 1. Expected <200> to be equal to <204>, but was not.
E 2. Expected <['Kent', 'Bunny', 'Doug', 'New', 'New', 'New']> to not contain item <Kent>, but did.

Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope you have a better sense of how a dedicated fluent assertion library makes your framework much better and I hope you would use them going forwards. That’s it for this post. We shall see how to work with XML and JSON data types in the next posts in the series

If you found this post useful, Do share it with a friend or colleague and if you have thoughts, I’d be more than happy to chat over at twitter or comments. Until next time. Happy Testing and Coding.

Top comments (0)