In the past few years, Ansible has become one of the most popular infrastructure as code tools. It allows you to manage infrastructure configurations with ease and without any problems with scaling. To avoid code repetition, Ansible created roles. An Ansible role is a set of reusable configurations that can be applied multiple times. Usually, we create one Ansible role per service that we want to install. For example, if we want to configure a WordPress Debian machine, we will install (at least) three Ansible roles:
- Apache2 : An Ansible role that will install Apache2 and configure vhosts.
- Mysql : An Ansible role that will install the WordPress database.
- PHP : An Ansible role that will install the WordPress runtime.
You can find a lot of community Ansible roles on the Ansible Galaxy website. However, you can also host your own private Ansible roles on any Git repository and install them before applying them to your infrastructure.
Like any piece of code, whether it is infrastructure as code or application code, it needs to be tested before being applied to environments. These unit tests need to prove that the Ansible role installs and configures the service without any misconfigurations. To perform these unit tests, the community created Molecule.
In this article, I will explain how Molecule works and how it can be used to perform your tests and decrease your Ansible role development time.
Installation & role implementation
Installation
You can easily install Molecule using its PyPI dedicated package : molecule .
Use the following command :
pip3 install ansible # if not already installed
pip3 install moleculeTo verify molecule installation, use the following command:
molecule --version⚠️ If you never installed ansible before, you may have an issue like this (it can be the same for molecule) :
-bash: ansible: command not foundThis means that the Ansible command is not in your $PATH. To fix this issue, add the following line to your shell profile (“~/.bashrc” or “~/.zshrc” depending on what you use) this line :
# Example of ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"Then source your profile :
source ~/.bashrcThat’s it ! You are ready to go !
Role implementation
The directory structure of an Ansible role has been standardized by the Ansible community. Any Ansible role should look like this:
roles-example/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.ymlIf you want details on the purpose of each folder, I recommend you to read the official documentation .
This directory structure can be initialized with the command :
ansible-galaxy init <ROLE_NAME>However, by default, Molecule is not added to ansible role directory. You need to add it with the following command :
molecule init scenario <scenario_name>💡If you don’t specify the scenario name, molecule will create a scenario with the default name : default
This command creates a molecule folder with the following folder/files :
.
└── default
├── converge.yml
├── create.yml
├── destroy.yml
├── INSTALL.rst
├── molecule.yml
└── verify.ymlThe first subfolder (in our case, “default”) is the name of the scenario. You can have as many scenarios (with different names) as you want. Each file in the scenario folder has a specific purpose that will be explained in the next section.
A scenario story
In this section, we will define what is a molecule scenario and how it can help you to perform your unit tests.
Default steps
A Molecule scenario is a set of steps performed in a specific order, where each step is an Ansible playbook. Usually, the steps defined in a Molecule scenario are:

Even if the content of these steps is FULLY customizable, the main purpose of each step is as follows :
- Create : Create the environment where we will test our Ansible role. This environment could be anything as long as you can create it with Ansible. For example, famous environments are :
- Local dockers
- Local virtual machines
- Virtual machines deployed on a cloud provider.
- Prepare : After creating your environment, you may need to prepare it. The prepare step will help you initialize your environment. A good practice is to install your role requirements during this step.
- Converge : The converge phase is the step where you will apply the role that you want to test.
- Verify : The verify step is where you will perform unit tests on your environment. Because your role will be installed (in the converge step), you will be able to test it and verify that it is working correctly. A powerful Ansible module used to verify a configuration (or other things) is ansible.builtin.assert
- Destroy : Step to destroy the environment created (in the create step).
It exists others steps that could be integrated but are less frequently used :
- Idempotence : This step launches your converge step a second time. If, for some reason, one of the tasks defined in your Ansible output is a “changed,” the idempotence check will fail, giving you the specific task that is not idempotent.
- Cleanup : This step is usually used to clean configuration outside of the environment you have created with the create step
- Side-effect : This step is used to perform side-effects on your environment. By “side-effect” we define any actions that could disturb your environment. It can be useful to test high-availability , resiliency etc ..
With these steps, the schema could looks like :

Step dependency
At this point of the article, you may wonder what is the purpose of the molecule.yml file.
This file is used to configure your entire scenario, including step dependencies. Each step in your scenario can depend on other steps, and this file specifies those dependencies. For example, the prepare step depends on the create step because you cannot prepare an environment that has not been created yet.You can find the details of each dependency in this documentation. To summarize the steps performed based on the CLI command, it would look like this:

If you want to overwrite the dependency of a step, you can modify the molecule.yml file :
scenario:
<step_name>_sequence:
- step_name_1
- step_name_2
- step_name_3For example if you want that the converge step depends ONLY on the prepare step :
scenario:
converge_sequence:
- prepare💡 You can check the dependency of a step with the following command :
molecule matrix <name_of_step>As you can see in the above diagram, the molecule test command launches all the scenario steps. We typically use this command in CI/CD pipelines to perform all tests on our Ansible role.
Platforms
When configuring a molecule scenario via the molecule.yml file, we need to specify on which platform (operating system, environment, version, etc.) we will run our tests.
We could hard-code this information in our create.yml playbook, but this would limit us to creating only one environment.
To create multiple and dynamic environments with different versions, we use the platforms parameter in the molecule.yml file. This parameter is a list of variables that define the values for our environments, and these values are available in each step of the scenario as variables. With this parameter, we can use a loop in our playbooks to deploy multiple environments and test our role on various platforms.
For example we could test our role on 2 different Debian version :
# molecule.yml platform example
platforms:
- name: role-debian11
ami: debian-11-amd64-*
owner: 136693071363
type: t3.micro
- name: role-debian10
ami: debian-10-amd64-*
owner: 136693071363
type: t3.microAnd use these parameters within the create.yml :
# Example of step in create.yml
- name: Sample example using loops
ansible.builtin.template:
src: "{{ playbook_dir }}/script.sh.j2"
dest: "{{ playbook_dir }}/script.sh"
mode: 0700
vars:
platforms: "{{ molecule_yml.platforms }}"⚠️ If you plan to write a personalized create step, remember to dump your environment config inside the molecule cache folder. For example, if you want to be able to connect to a virtual machine :
- name: Dump instance config
ansible.builtin.copy:
content: |
---
{% for instance in instances %}
- address: {{ instance.ansible_facts.instance_conf_dict.address }}
identity_file: {{ instance.ansible_facts.instance_conf_dict.identity_file }}
instance: {{ instance.ansible_facts.instance_conf_dict.instance }}
port: {{ instance.ansible_facts.instance_conf_dict.port }}
user: {{ instance.ansible_facts.instance_conf_dict.user }}
{% endfor %}
dest: "{{ molecule_instance_config }}"
mode: 0600
vars:
instances: "{{ instance_conf_dict.results }}"💡 The molecule_instance_config variable is the variable that defines the molecule cache folder.
Molecule key values
Molecule is a tool that brings a lot of value to your DevOps team. It allows you to:
- Create Ansible unit tests: You can create unit tests to test the functionality of your Ansible role. It is possible to perform these tests locally or through a CI/CD pipeline.
- Create a development environment easily: When a DevOps engineer starts to code an Ansible role, they need to have access to an environment to test their configuration. Molecule allows you to provide this environment effortlessly. Moreover, the DevOps engineer will be able to connect to their environment with a single command: molecule login. The type of connection (SSH, Winrm, etc.) depends on the information provided inside the molecule cache.
- Reproducible environment and tests: Because molecule scenario definitions are hosted within the Git repository, the scenarios are sharable with your whole team. Moreover, during an update of the Ansible role, the DevOps team will be able to deploy the same test environment that was created during the initial development of the role. This aspect of Molecule helps your DevOps team to focus only on the role development.
However, before using Molecule, you will need :
- A strong understanding of Ansible: Molecule itself is based on Ansible. Ansible playbooks write each step (by default). Before creating your own scenarios, you will need to understand each necessary step and know how to code them using Ansible.
- To “reverse engineer” Molecule: I have been using Ansible and Molecule for years now, and I wouldn’t be able to create good scenarios without understanding how Molecule works. I highly recommend that you spend some time studying the Molecule cache folder: ~/.cache/molecule/<your_role>/.
Conclusion
To conclude, we can say that Molecule is an indispensable tool for any Ansible developer. It allows you to create a reproducible environment in which to perform unit tests for your Ansible roles.
This tool is usable during the development phase and as a CI/CD tool to perform unit tests before deployment in production.
However, it is important to have a strong knowledge of Ansible and a good understanding of Molecule before using it properly.
Would you like to read more articles by Tekos’s Team? Everything’s here.

