12.5 Testing Your Module
Since we now have our module inside our new collection we want to test it. For that the ansible tooling has a set of modules to help us with different kinds of testing.
Ansible content should be tested in three ways:
- Sanity Testing - Mainly static code analysis of different kinds
- Unit Testing - Testing the logic of you code
- Integration Testing - Testing how you ansible content behaves when integrated with other ansible content
We will have a look at how to set up and create these kind of tests. But first let’s have a look on how these tests are executed.
Task 1 - tox-ansible
To perform tests on Ansible content tox
alongside with the tox plugin tox-ansible
is used.
tox
is a Python test-automation framework, which allows you to run tests in different environments.
When we created the collection using the ansible-creator
tool, it created a tox-ansible.ini
file which we can use as a tox configuration.
In this file, we can configure what Python versions and Ansible versions to perform test against. This can be very powerful especially when running extensive CI pipelines. However, we will focus on our local Python and Ansible versions for now. Try to solve the following tasks:
- Can you list all available tests?
- What Python and Ansible versions are available on you lab server?
- Can you configure the tox-ansible plugin to use your local Python and Ansible versions? (Use the tox ansible documentation)
Solution Task 1
With the pipenv activated and inside the collection directory run:
1
tox list --ansible -c tox-ansible.ini
You can find out which Python and Ansible versions are available by running:
1 2 3 4 5 6 7 8 9 10 11 12
$ python -V Python 3.12.5 $ ansible --version ansible [core 2.18.6] config file = /home/ansible/techlab/ansible-module-development/ansible.cfg configured module search path = ['/home/ansible/techlab/ansible-module-development/library'] ansible python module location = /home/ansible/.local/share/virtualenvs/ansible-module-development-J9Af2H_I/lib/python3.12/site-packages/ansible ansible collection location = /home/ansible/.ansible/collections:/usr/share/ansible/collections executable location = /home/ansible/.local/share/virtualenvs/ansible-module-development-J9Af2H_I/bin/ansible python version = 3.12.5 (main, Apr 2 2025, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-5)] (/home/ansible/.local/share/virtualenvs/ansible-module-development-J9Af2H_I/bin/python) jinja version = 3.1.6 libyaml = True
You can configure tox-ansible to use your local Python and Ansible versions by skipping all versions that do not match your local Python and Ansible versions. The following lines should do the trick:
1 2 3 4 5 6 7 8 9
[ansible] skip = py3.10 py3.11 py3.13 2.16 2.17 devel milestone
Task 2 - Sanity Testing our collection
Let’s try to run sanity tests against our collection. List the available sanity tests again and choose to run the sanity tests.
In the test output you will encounter some issues regarding the sample plugins, feel free to either remove these plugins or ignore them.
Does the schroedingers_cat
plugin pass the sanity tests?
Try to fix all the tests.
Solution Task 2
You can execute a specific sanity test by running:
|
|
Those plugins can be removed:
|
|
Task 3 - Unit Testing our collection
Unit tests can be run similarly to sanity tests but with the unit
environment:
|
|
As you can see from the output of this command there are already some basic tests present in the collection. We will ignore them for now and focus on writing our own tests against our collection to make sure our module works as expected.
The Ansible Community Documentation has an extensive documentation page about unit testing modules that you can find here. Keep this page in mind since it may come in handy as a reference for the following tasks. It may also be helpful if you are not familiar with unit testing and want to learn more on what unit tests are and why we need them.
For now, we will start by creating a test file for the schroedingers_cat
module in the tests/unit/plugins/modules
directory and adding some test cases in it.
In this lab we will use pytest style test cases.
Can you implement the following unit test cases?
- The module should always return a
cat_state
on exit. - The module should always return a cat state of
dead and alive
when theforce_box_open
argument is set toFalse
(default). - The module should always return a cat state of
alive
ordead
when theforce_box_open
argument is set toTrue
.
Solution Task 3
First create the unit test file:
|
|
To write isolated unit tests we will need some of the utilities introduced in the Ansible Community Documentation. First we need to address the question of how we can control which arguments our module will be called with in the unit test.
The set_module_args
function from the documentation can be used to set the arguments that will be passed to the module:
|
|
With this approach we leverage a global variable which ansible uses to store the passed arguments.
Then we can set the arguments to the module by calling the set_module_args
function in the test cases.
The second issue we need to address is to verify the termination status of the module.
It either will call the exit_json
function or the fail_json
function.
Using pytest fixtures, we can mock the AnsibleModule functions:
|
|
Now let’s implement the unit tests for the cases mentioned above:
|
|
Now we can run the unit tests using tox just like we did for the sanity tests:
|
|
Task 4 - Integration Tests
As you saw in the available tox environments we have integration-py3.12-2.18
environment.
Let’s have a look at what this environment is doing.
Looking inside the tests
directory we can see that besides the unit
directory that we saw earlier there is a integration
directory.
In this directory we have a subdirectory targets
in which we can write our integration tests in form of ansible roles.
tox
will then use these roles to run them inside molecule test scenarios. molecule
is a test framework for Ansible content.
So we might go ahead and write a role in the targets
directory called schroedingers_cat
.
In this role we will write our integration tests by calling our module, registering its output and inspecting the result using the assert module.
Try to test the following cases:
- Calling the module with
force_box_open
set toFalse
(default) should result in a cat state ofdead and alive
. - Calling the module with
force_box_open
set toTrue
should result in a cat state ofalive
ordead
.
Try to verify that by running the role in the integration-py3.12-2.18
environment.
While doing so you might at first encounter an error regarding an integration_hello_world
test failing.
Can you figure out how to set up molecule in the extensions
directory to make run your new test instead of the hello_world
test?
Solution Task 4
First you need to create a molecule scenario in the extensions/molecule
directory.
You can do that by renaming the integration_hello_world
scenario to integration_schroedingers_cat
.
Next you need to create a role in the targets
directory called schroedingers_cat
.
Inside this role you can create a file called tasks/main.yml
and add write the test cases, for example:
|
|
Run the role in the integration-py3.12-2.18
environment and verify that the tests pass.
All done?
- Try reading up on molecule. What is a scenario? What is a test sequence? What is being configured in the molecule.yml?