Test automation with Ansible

September 20, 2021

Automation

Did you know that you can automate your REST API tests using Ansible? This tool which is usually associated with app and infrastructure automation can also be used to perform API tests.

In this article, we will take a brief look at Ansible test automation.

Ansible core module

No additional modules are needed to start writing tests – core Ansible module called „uri” will be used. This module ensures communication with api resources and allows to conveniently check the operation of REST API.

In the following sections, we will write sample plays that will be used for api tests.

Play’s structure

Play used for API testing will take the following form:

- name: Template
  hosts: localhost
  tasks:
    - name: Template task
      uri:
        url: "/some/path"
        method: POST
        body_format: json
        body: "param: value"
        validate_certs: false
        return_content: yes
      register: return_data

The task „Template task” is designed to:

  • send POST request (method: POST) to the endpoint „/some/path” (url: “/some/path”),
  • send username and password in the request’s body (body: […]) in JSON format (body_format: json),
  • save the response from the API to the variable „return_data” (register: return_data).

For testing purposes, it is worth using the „validate_certs” option, which allows the use of self-signed certificates without getting errors.

Caution! By default, Ansible expect a „200 OK” response to conclude that the request was successful. If you need to check a different response code, use the „status_code: expected status code” option.

Example tests – logging into the application, sending GET request and logging out

In this section, we will use Ansible to obtain user’s authorization token, send GET request to the secured endpoint and then send a user logout request. These simple tests will check basic operations performed by the API.

Logging in

To login to the API using a POST request, use the following play:

- name: Login to the system
  hosts: localhost
  tasks:
    - name: Login to the system
      uri:
        url: "api/auth/login"
        method: POST
        body_format: json
        body: "{\"username\": \"user123\", \"password\": \"1qaz@WSX\"}"
        validate_certs: false
        return_content: yes
      register: token_data

This request uses the aforementioned template, only the request body was changed to take a form suitable for logging in with a username and password.

After executing this request, the authorization token will be saved to the „token_data” variable (register: token_data).

Sending GET request

To send a GET request to the API resource using the previously obtained token to authorize the user, use the following play:

- name: Obtain list of objects
  hosts: localhost
  tasks:
    - name: Obtain objects
      uri:
        url: "api/some/other/path"
        headers:
          Authorization: "Bearer {{ token_data.json.token }}"
        validate_certs: false
        return_content: yes
      register: data_objects_all
    - name: Print objects
      debug:
         msg:
           - "{{ item.id }}"
      loop: "{{ data_objects_all.json }}"
      loop_control:
         label: "{{ item.id }}"
         extended: yes

The code above sends a GET request (it is the default method so you do not have to specify it like you did with POST request) to the API resource, and then prints the received data in the terminal window.

The first task uses the template with an additional code responsible for user authorization (headers: […]). This snippet will add the „Authorization: Bearer ” header to the request. Note that in order to refer to a variable defined earlier in the code, you use „{{ variable_name }}” construct.

In our case, we want to get data from a variable in JSON format from the parameter called „token” so we use „{{ token_data.json.token }}”

The second task is designed to list the received objects. For this purpose, we will use „debug” and „msg” instructions and the „loop” to go over all elements received. The iteration will be performed on the received objects in JSON format (loop: „{{ data_objects_all.json }}”). In order not to print the whole object during each step of the loop, „label” option will be used (label: „{{ item. id }}”).

Logging out

To logout we send a DELETE request to the endpoint using the following play:

- name: Logout
  hosts: localhost
  tasks:
    - name: Delete user session
      uri:
        url: "api/auth/path"
        method: DELETE
        status_code: 204
        headers:
          Authorization: "Bearer {{ token_data.json.token }}"
        validate_certs: false

Once again we use the template and change it so that the DELETE method is used (method: delete) and the task expects response code „204 No Content” (status_code: 204). Again, we add the header to inform the server about our identity.

Summary

The above examples show that Ansible can be used to quickly write and perform tests for REST APIs. Thanks to the built-in core „uri” module, API testing can be started immediately after installing Ansible and the code structure itself is clear and transparent.