molecule
Molecule is the testing framework for Ansible content. It manages the full lifecycle of test infrastructure — provisioning instances, applying your Ansible content, running verification, and tearing everything down. Molecule supports testing against containers, virtual machines, cloud infrastructure, network devices, and APIs.
Molecule uses scenario-based configuration where each scenario is a self-contained test with its own infrastructure, playbooks, and verification steps.
Installation
Section titled “Installation”# Via the full suite (recommended)pip install ansible-dev-tools
# Standalonepip install molecule
# With Docker driverpip install molecule-plugins[docker]
# With Podman driverpip install molecule-plugins[podman]Verify installation:
molecule --versionCore concepts
Section titled “Core concepts”Scenarios
Section titled “Scenarios”A scenario is a self-contained test case with its own:
- Infrastructure definition (what to create)
- Converge playbook (what to test)
- Verification playbook (how to validate)
- Destroy playbook (how to clean up)
Scenarios live under extensions/molecule/ (for collections) or molecule/ (for roles and playbooks):
extensions/molecule/├── default/│ ├── molecule.yml│ ├── create.yml│ ├── converge.yml│ ├── verify.yml│ └── destroy.yml└── integration/ ├── molecule.yml ├── converge.yml └── verify.ymlTest sequence
Section titled “Test sequence”Molecule executes tests as an ordered sequence of actions:
dependency → cleanup → destroy → syntax → create → prepare →converge → idempotence → side_effect → verify → cleanup → destroyEach action maps to a playbook or built-in check:
| Action | Playbook | Purpose |
|---|---|---|
dependency |
— | Install role/collection dependencies |
cleanup |
cleanup.yml |
Clean external resources before destroy |
destroy |
destroy.yml |
Tear down test infrastructure |
syntax |
— | Ansible syntax check on converge playbook |
create |
create.yml |
Provision test infrastructure |
prepare |
prepare.yml |
Pre-configure instances (runs once) |
converge |
converge.yml |
Apply the role/playbook under test |
idempotence |
— | Re-run converge, assert no changes |
side_effect |
side_effect.yml |
Trigger side effects (e.g., failover) |
verify |
verify.yml |
Run verification assertions |
Drivers
Section titled “Drivers”Drivers manage the test infrastructure lifecycle. Available via the molecule-plugins package:
| Driver | Install extra | Description |
|---|---|---|
docker |
[docker] |
Docker containers |
podman |
[podman] |
Podman containers |
vagrant |
[vagrant] |
Vagrant VMs |
ec2 |
[ec2] |
AWS EC2 instances |
gce |
[gce] |
Google Compute Engine |
azure |
[azure] |
Azure VMs |
openstack |
[openstack] |
OpenStack instances |
The default (delegated) driver is built into Molecule core — you provide your own create.yml and destroy.yml playbooks using any Ansible modules.
Additional drivers:
| Driver | Package | Description |
|---|---|---|
kubevirt |
molecule-kubevirt |
KubeVirt VMs |
Configuration
Section titled “Configuration”Ansible-native configuration (recommended)
Section titled “Ansible-native configuration (recommended)”The modern configuration approach uses molecule.yml with four top-level sections:
---ansible: executor: backend: ansible-playbook args: ansible_playbook: - --inventory=inventory/ - --extra-vars=environment=test env: ANSIBLE_FORCE_COLOR: "true" ANSIBLE_HOST_KEY_CHECKING: "false" ANSIBLE_STDOUT_CALLBACK: yaml cfg: defaults: host_key_checking: false gathering: smart timeout: 30 ssh_connection: pipelining: true playbooks: create: create.yml destroy: destroy.yml converge: converge.yml prepare: prepare.yml verify: verify.yml cleanup: cleanup.yml side_effect: side_effect.yml
scenario: test_sequence: - create - converge - verify - destroy
shared_state: true
verifier: name: ansiblePre-ansible-native configuration (legacy)
Section titled “Pre-ansible-native configuration (legacy)”The legacy format uses driver, platforms, and provisioner sections:
---driver: name: dockerplatforms: - name: instance-1 image: ubuntu:22.04 groups: - web_servers - name: instance-2 image: centos:stream9 groups: - db_serversprovisioner: name: ansible config_options: defaults: host_key_checking: false env: ANSIBLE_STDOUT_CALLBACK: yaml playbooks: converge: converge.yml inventory: group_vars: all: app_version: "2.0"verifier: name: ansiblescenario: test_sequence: - dependency - cleanup - destroy - syntax - create - prepare - converge - idempotence - verify - cleanup - destroydependency: name: galaxy options: role-file: requirements.yml requirements-file: collections.ymlConfiguration file locations
Section titled “Configuration file locations”Molecule searches for configuration in this order:
$HOME/.config/molecule/config.yml— global defaults- Project root
config.yml— project-wide defaults extensions/molecule/config.yml— collection base config- Per-scenario
molecule.yml— scenario-specific overrides
Variable substitution
Section titled “Variable substitution”molecule.yml supports shell-style variable substitution:
platforms: - name: instance-${MOLECULE_SCENARIO_NAME} image: ${CONTAINER_IMAGE:-ubuntu:22.04}Environment variables
Section titled “Environment variables”| Variable | Description |
|---|---|
MOLECULE_DEBUG |
Enable debug output |
MOLECULE_SCENARIO_NAME |
Current scenario name |
MOLECULE_EPHEMERAL_DIRECTORY |
Temp directory for scenario |
MOLECULE_SCENARIO_DIRECTORY |
Path to scenario directory |
MOLECULE_PROJECT_DIRECTORY |
Path to project root |
MOLECULE_INVENTORY_FILE |
Generated inventory path |
MOLECULE_INSTANCE_CONFIG |
Instance configuration path |
MOLECULE_VERBOSITY |
Verbosity level |
Verifiers
Section titled “Verifiers”Ansible verifier (default)
Section titled “Ansible verifier (default)”The default verifier runs verify.yml with Ansible assertion modules:
---- name: Verify hosts: all gather_facts: false tasks: - name: Check that nginx is installed ansible.builtin.package_facts: manager: auto
- name: Assert nginx is present ansible.builtin.assert: that: - "'nginx' in ansible_facts.packages" fail_msg: "nginx is not installed"
- name: Check nginx is running ansible.builtin.service_facts:
- name: Assert nginx service is active ansible.builtin.assert: that: - "ansible_facts.services['nginx.service'].state == 'running'"Testinfra verifier
Section titled “Testinfra verifier”For Python-based testing with pytest/testinfra:
verifier: name: testinfra options: n: 1 verbose: true additional_files_or_dirs: - ../shared_tests/def test_nginx_installed(host): nginx = host.package("nginx") assert nginx.is_installed
def test_nginx_running(host): nginx = host.service("nginx") assert nginx.is_running assert nginx.is_enabledCLI reference
Section titled “CLI reference”Running tests
Section titled “Running tests”# Run the full test sequence for the default scenariomolecule test
# Test a specific scenariomolecule test -s integration
# Test all scenariosmolecule test --all
# Run scenarios in parallelmolecule test --all --parallel
# Run with multiple workersmolecule test --all --workers 4
# Pass extra arguments to ansible-playbookmolecule converge -- --extra-vars="debug=true"Development workflow commands
Section titled “Development workflow commands”# Create instances onlymolecule create
# Apply the converge playbook (create if needed)molecule converge
# Run verificationmolecule verify
# Destroy instancesmolecule destroy
# Destroy all scenariosmolecule destroy --all
# Prepare instances (run once)molecule prepare
# Check idempotencemolecule idempotence
# Interactive login to an instancemolecule login --host instance-1
# Run syntax checkmolecule syntaxUtility commands
Section titled “Utility commands”# Initialize a new scenariomolecule init scenario my_scenario
# List scenario statusmolecule list
# Show the action matrix for a commandmolecule matrix test
# Reset molecule temporary filesmolecule reset
# List available driversmolecule driversGlobal flags
Section titled “Global flags”| Flag | Description |
|---|---|
--debug |
Verbose output (passes -vvv to ansible-playbook) |
-s, --scenario-name |
Target specific scenario |
--parallel / --no-parallel |
Run scenarios concurrently (deprecated, use --workers) |
--workers N |
Number of concurrent scenario workers |
Custom test sequences
Section titled “Custom test sequences”Configure which actions run for each command:
scenario: create_sequence: - dependency - create - prepare converge_sequence: - dependency - create - prepare - converge destroy_sequence: - cleanup - destroy test_sequence: - dependency - cleanup - destroy - syntax - create - prepare - converge - idempotence - verify - cleanup - destroyMultiple verify and side_effect steps
Section titled “Multiple verify and side_effect steps”For complex test scenarios, include multiple side effects and verification steps:
test_sequence: - converge - side_effect reboot.yaml - verify after_reboot/ - side_effect alter_configs.yaml - converge - verifyExecutor backends
Section titled “Executor backends”ansible-playbook (default)
Section titled “ansible-playbook (default)”Runs playbooks directly using locally installed Ansible:
ansible: executor: backend: ansible-playbook args: ansible_playbook: - --inventory=inventory/ansible-navigator
Section titled “ansible-navigator”Runs playbooks inside execution environments for reproducible testing:
ansible: executor: backend: ansible-navigator args: ansible_navigator: - --execution-environment-image=custom-ee:latest - --mode=stdoutCI/CD integration
Section titled “CI/CD integration”GitHub Actions
Section titled “GitHub Actions”name: Moleculeon: [push, pull_request]
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install dependencies run: pip install ansible-dev-tools molecule-plugins[docker] - name: Run molecule run: molecule test --all env: PY_COLORS: "1" ANSIBLE_FORCE_COLOR: "1"GitLab CI
Section titled “GitLab CI”molecule: image: ghcr.io/ansible/community-ansible-dev-tools:latest services: - docker:dind variables: DOCKER_HOST: tcp://docker:2375 script: - molecule test --allTips for CI
Section titled “Tips for CI”- Set
PY_COLORS=1andANSIBLE_FORCE_COLOR=1to force colored output - Use
--workersfor parallel scenario execution - Set unique
MOLECULE_EPHEMERAL_DIRECTORYper parallel job to avoid conflicts - Use the
community-ansible-dev-toolscontainer image for pre-installed tooling
Shared state
Section titled “Shared state”Enable shared state to let scenarios share ephemeral data for efficient multi-scenario testing:
shared_state: trueThis is useful when multiple scenarios test different aspects of the same infrastructure and you want to avoid reprovisioning for each scenario.
Editor integration
Section titled “Editor integration”Projects scaffolded by ansible-creator include Molecule scenarios by default. The VS Code extension recognizes Molecule directory structures and provides:
- File detection for
molecule.ymland scenario playbooks - Ansible language support in all Molecule playbooks
- Integration with ansible-lint for scenario files
Next steps
Section titled “Next steps”Your scenarios pass locally. Now scale your testing and prepare for execution:
- Run a full test matrix with tox-ansible — test across Python versions and ansible-core releases
- Execute playbooks with ansible-navigator — run your content in execution environments
- CLI Reference — complete molecule.yml schema, environment variables, drivers, and CLI flags
- PyPI: molecule
- GitHub: ansible/molecule
- GitHub: molecule-plugins