Note: Ansible Collections are currently in tech preview. The details of this blog post may be outdated by the time you read this, though I will try to keep things updated if possible.
Ansible 2.8 and 2.9 introduced a new type of Ansible content, a 'Collection'. Collections are still in tech preview state, so things are prone to change, but one thing that the Ansible team has been working on is improving ansible-test
to be able to test modules, plugins, and roles in Collections (previously it was only used for testing Ansible core).
ansible-test
currently requires your Collection be in a very specific path, either:
- Inside the current Ansible source tree (e.g. if you're developing against Ansible core)
- Inside a specific collection heirarchy path, like
{...}/ansible_collections/{namespace}/{collection}/
You have to make sure your collection is in that specific path—with an empty directory named ansible_collections
, then a directory for the namespace
, and finally a directory for the collection
itself. I opened an issue in the Ansible issue queue asking if maybe ansible-test
can be a little more lenient and allow running tests in an arbitrary collection directory, since not everyone likes cloning into extremely rigid directory structures.
Once you have the collection in the right path, you can run:
ansible-test integration --docker ubuntu1804
I always use the --docker
option and specify a particular OS, that way I can be sure the tests are running inside a clean, ephemeral environment (and not locally in my workspace). Ansible's official maintained container OS images for ansible-test
are listed in the documentation, but you can also use a custom image by specifying it directly, e.g. ansible-test integration --docker geerlingguy/docker-ubuntu1804-ansible
If you're using a local image or otherwise don't want to try pulling the image from a remote repository, also pass the
--docker-no-pull
option.
Creating an integration test
ansible-test
also requires tests be in a specific directory structure in order for them to be picked up. You must put all test code inside a directory named tests
in the root of your Collection (I opened a feature request to see if the directory naming can be relaxed, too). Then integration tests go inside tests/integration
.
You can have one or more test 'targets' (e.g. one target for each role, module, or plugin in your Collection, or one target for one kind of integration test, and another for a different kind), each one inside a targets
directory. In my case, I'm testing the geerlingguy.php_roles Collection, so I want an integration test for the php
role, to make sure it works. I'll create the directory structure:
tests/
integration/
targets/
php/
This php
directory will be run as a role against the test environment—as will any other directory placed inside targets
.
Note: Currently,
ansible-test
will run every role/target, in succession, against the same test environment container; so things changed by the first target would affect the second target's environment. I opened an issue asking if there could be a way to provide a clean environment for each integration test (something Molecule can do currently), but for now, keep this in mind as you need to do manual cleanup between roles if you want to run them all in one suite.
As with any Ansible role, the minimum requirement is a tasks/main.yml
file, which will be run as a normal included Ansible task file. In this task file, you can do anything you normally would do with ansible, like include a role, use modules to test certain conditions, call an API, etc.
To verify your tests are working, add a task in tasks/main.yml
like:
- name: Debug test.
debug: msg="Testing 1, 2, 3."
Then when you run ansible-test you should get something like:
$ ansible-test integration --docker ubuntu1804
...
Running php_role_test integration test role
PLAY [testhost] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [testhost]
TASK [php_role_test : Debug test.] *********************************************
ok: [testhost] => {
"msg": "Testing 1, 2, 3."
}
PLAY RECAP *********************************************************************
testhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
If you want the integration test to run a role in your collection, be sure to use the entire role path with namespace:
- include_role:
name: geerlingguy.php_roles.php
Note: Currently, the only way to use collection or role dependencies inside the docker test container is by installing them manually, directly inside your collection's directories, before running
ansible-test
. There is an open issue to get this resolved so collection dependencies can work correctly withansible-test --docker
: Support testing collections with deps using --docker.Additional Note: Currently, the only way to test for role idempotence (that is, if you run it multiple times, it only makes changes the first time, and just ensures state in follow-up runs) is to build your own checks in a
runme.sh
shell script. See the following issue for progress in making idempotence testing easier: ansible-test idempotence tests for roles in Ansible Collections.
For right now, I'd recommend sticking with Molecule for role testing, and using ansible-test
more for module and plugin testing. I believe the long-term goal is to make it so Molecule can (if desired) be used as a more developer-friendly frontend to the ansible-test
tool, but a lot of these things are still moving parts, as noted in the beginning of this post.
Comments
Thank you for posting this, it was very helpful but I do have a question. I am writing an action plugin that works with specific networking devices and returns an error if the host does not match the expected device type. I would like to test this but as far as I know there is no dockerized version of this device so I was wondering if it is possible to specify a host or hosts to run the role against as I would in a playbook rather than running it on a docker container