Open-Source Wikis

/

Ansible

/

How to contribute

/

Testing

ansible/ansible

Testing

ansible-core has its own test runner, ansible-test, packaged separately from the engine at test/lib/ansible_test/. It handles three flavors of tests — sanity, unit, integration — across Docker, Podman, virtualenv, and remote-host backends. This page is a tour.

ansible-test, in 60 seconds

bin/ansible-test is a symlink to test/lib/ansible_test/_util/target/cli/ansible_test_cli_stub.py. The stub bootstraps ansible_test from the test/lib/ package and dispatches to the real command (sanity, units, integration, coverage, etc.).

Common entry points:

ansible-test sanity         # Lint + static analysis
ansible-test units          # pytest-based unit tests
ansible-test integration    # Real-world playbook tests
ansible-test coverage       # Aggregate coverage across the above
ansible-test env            # Print the current ansible-test environment
ansible-test windows-integration  # Windows-only integration tests via WinRM
ansible-test network-integration  # Network-platform tests

Available containers are listed in test/lib/ansible_test/_data/completion/docker.txt. Use --docker default for sanity/units; pick a distro-specific container (ubuntu2204, ubuntu2404, fedora41, etc.) for integration.

Sanity tests

Sanity tests live under test/sanity/. They are not "tests" in the unit sense — they're lints, static analysis, and structural checks. The full set is reachable via:

ansible-test sanity --list-tests

A non-exhaustive sample:

Test What it checks
pep8 PEP-8 with the project's local relaxations (line limit 160, E402 ignored)
pylint Custom pylint plugins under test/sanity/code-smell/ and a curated rule set
mypy Static type-checking for the controller
validate-modules Module documentation correctness and argument-spec validity
import Each Python file is importable (no syntax errors, no missing deps in module_utils)
no-smart-quotes Disallow Unicode smart quotes in source files
runtime-metadata The redirect map in lib/ansible/config/ansible_builtin_runtime.yml is well-formed
bin-symlinks bin/* symlinks all resolve correctly
boilerplate Required from __future__ import annotations and license headers

Run all of them, scoped to your changes:

ansible-test sanity -v --docker default <changed paths>

Unit tests

Unit tests sit under test/units/, mirroring lib/ansible/:

test/units/cli/         ← tests for lib/ansible/cli/
test/units/executor/    ← tests for lib/ansible/executor/
test/units/plugins/     ← tests for lib/ansible/plugins/
test/units/modules/     ← tests for lib/ansible/modules/
test/units/playbook/    ← tests for lib/ansible/playbook/
test/units/parsing/     ← tests for lib/ansible/parsing/
test/units/galaxy/      ← tests for lib/ansible/galaxy/
test/units/inventory/   ← tests for lib/ansible/inventory/
test/units/template/    ← tests for the templating layer
test/units/utils/       ← tests for lib/ansible/utils/
test/units/vars/        ← tests for lib/ansible/vars/
test/units/regex/       ← regex-specific helpers

They use plain pytest. Per the AGENTS.md:

Unit tests should be pytest style, and functional rather than tightly coupled to mocking.

In other words: prefer testing real behavior with real objects where possible. Mocks should be at the I/O boundary (network, filesystem, subprocess) — not at every internal call.

Run a single file:

ansible-test units -v --docker default test/units/modules/test_command.py

With coverage:

ansible-test units -v --docker default --coverage

Integration tests

Integration tests live under test/integration/targets/<name>/. Each target is a directory of playbooks and supporting files exercising one feature or module against a real (containerized) target.

The structure of a typical target:

test/integration/targets/foo/
├── aliases               # Test categorization (controller-only? hidden?)
├── meta/
│   └── main.yml          # role-style metadata
├── tasks/
│   └── main.yml          # what the test actually does
├── files/
└── vars/

The aliases file is small but important. It controls:

  • Whether the target is run in CI by default (disabled opts out).
  • Whether the test runs on the controller (context/controller) or a separate target (context/target).
  • Resource needs (needs/file/..., needs/target/...).
  • Distro filters (skip/macos, skip/freebsd).

Run a target:

ansible-test integration -v --docker ubuntu2404 setup_remote_tmp_dir

The first invocation of --docker will pull or build the relevant image; subsequent runs reuse it.

Per AGENTS.md: integration tests are required for almost all plugin changes because they exercise the public API. Unit tests alone are not sufficient for action plugin or module changes.

Test isolation

Three backends are available:

  • --docker — runs everything inside the chosen image. Most reliable, recommended.
  • --podman — same as --docker but with Podman. Switch via --remote-stage/--remote-terminate.
  • --venv — runs in a host-local virtualenv. Fallback when containers aren't available; prone to host-environment leaks for unit and integration tests.

For Windows integration:

ansible-test windows-integration -v --windows 2022

For network platforms (cisco.ios, arista.eos, etc.) the tests live in those collections, but ansible-test network-integration can drive them.

Test-only support code

test/lib/ansible_test/ is a self-contained CLI of its own:

  • _internal/ — sanity test plugins, dependency manifests, container management, results parsing.
  • _data/ — payload files (sanity-test rule lists, requirements files for each Python version).
  • _util/ — helpers shipped to test environments (target-side scripts, controller bootstrapping).
  • config/ — example test configs.

test/support/ contains additional shared test infrastructure (helper roles, integration controller).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Testing – Ansible wiki | Factory