Testing patterns¶
Playbook examples here are ordinary Ansible playbooks. Follow the
developing-ansible skill for play structure, task conventions, Jinja2, and
boolean values.
Converge¶
- Call the role the way a real user calls it:
ansible.builtin.include_rolewith the fully qualified role name in a collection, orinclude_role/ aroles:entry in a standalone role. Playbook repositories canimport_playbookthe playbook under test. - Pass scenario-specific variables from inventory, group_vars, or the play, not by editing the role's own defaults.
- Do not reimplement the role in converge. If the role generates a config file, converge must not write that file itself.
- Keep converge deterministic and non-interactive so idempotence is meaningful.
Verify¶
Assert what an operator can observe: package state, service state and enablement,
file existence / ownership / mode / content, parsed configuration values,
listening sockets, HTTP or API behavior, command exit codes. Prefer read-only
modules and assert with explicit fail_msg.
- Do not re-run converge tasks in verify, and do not assert on internal task names, handler names, or the number of changed tasks.
- Avoid volatile values: timestamps, PIDs, ephemeral ports, generated secrets.
Idempotence¶
molecule idempotence re-runs converge on an already-converged instance and fails
if Ansible reports changes. Fix the role, not the test: use modules that report
change correctly, changed_when, creates / removes, and handlers.
- Read-only or externally tracked commands need
changed_when: false. - Tag genuinely non-idempotent tasks with
molecule-idempotence-notestto skip them only during the idempotence action;molecule-notest(ornotest) skips a task in every Molecule run. - Reboots, upgrades, and failure injection belong in
side_effect.yml, never inconverge.yml.
Services and systemd in containers¶
Plain containers do not run systemd as PID 1, so systemctl fails. To test
service-managing content:
- Use an init image (
ubi-initor a distribution init image) withcontainer_command: /sbin/initand, for Podman,container_systemd: alwaysin inventory. - systemd needs cgroup v2; rootless Podman additionally needs the v2 hierarchy delegated to the user.
wait_for_connectiononly proves the connection is up, not that boot finished. Wait on a unit orsystemctl is-system-runningwith retries before converge.- Some images run as a non-root user; add
become: trueor choose a root image. - A
Type=oneshotunit reportsstoppedafter a successful run. Assert enablement or the effect it produced instead ofrunning. - To test a service without systemd, verify the process or socket instead of the unit.