Lab Guide: Orchestrating Tests with tox-ansible

A guide to automating your testing workflow using the tox-ansible plugin.

Learning objectives

After completing this module, you will be able to:

  • Configure tox-ansible to auto-discover test environments

  • Run linting, unit, and integration tests through a unified tox interface

  • Target specific Ansible versions and test types using tox factors

Lab briefing

What is tox? tox is a generic virtual environment management and test command line tool. It is the standard for testing Python-based projects.

What is tox-ansible? tox-ansible is a plugin (installed by default in ansible-dev-tools) that makes tox "Ansible-aware." Instead of writing dozens of lines of configuration to tell tox how to run ansible-lint or molecule, the plugin scans your collection and automatically creates test environments for:

  • Linting: (ansible-lint)

  • Unit Tests: (pytest)

  • Sanity Tests: (ansible-test sanity)

  • Integration Tests: (molecule)

This "Convention over Configuration" approach allows you to run complex test matrices with a 5-line configuration file.

Lab guide: Hands-on tasks

Task 1: Verify the installation

Before we configure anything, let’s verify that tox and the plugin are installed and ready.

  1. Open the VS Code Terminal.

  2. Navigate to your collection root:

    cd /projects/ansible-dev-tools-workspace/mynamespace.mycollection/
  3. Check the tox version and plugins:

    tox --version

    Output analysis: You should see output similar to:

    $ tox --version
    ROOT: No loadable tox.ini or setup.cfg or pyproject.toml or tox.toml found, assuming empty tox.ini at /projects/ansible-dev-tools-workspace/mynamespace.mycollection
    4.53.0 from /projects/ansible-dev-tools-workspace/mynamespace.mycollection/.venv/lib64/python3.12/site-packages/tox/__init__.py
    registered plugins:
        tox-ansible-26.3.0 at /projects/ansible-dev-tools-workspace/mynamespace.mycollection/.venv/lib64/python3.12/site-packages/tox_ansible/plugin.py

    The ROOT: No loadable tox.ini message is expected — tox-ansible uses its own tox-ansible.ini file instead of tox.ini. Look for tox-ansible in the registered plugins list. This confirms the plugin is active.

Task 2: Configure tox-ansible

When ansible-creator scaffolded your collection, it created a tox-ansible.ini file. This is the configuration file for the tox-ansible plugin — it is separate from tox.ini on purpose, so it does not interfere with standard tox workflows.

The plugin uses tox-ansible.ini to control which Python versions and Ansible versions to include or skip in the test matrix. Without it, tox-ansible would generate environments for every supported Python and Ansible version combination, resulting in a very large matrix.

  1. Open the tox-ansible.ini file in the collection root and replace its contents with:

    [ansible]
    skip =
        py3.7
        py3.8
        py3.9
        py3.10
        py3.11
        py3.13
        py3.14
        2.9
        2.10
        2.11
        2.12
        2.13
        2.14
        2.15
        2.16
        2.17
        2.18
        2.19
        devel
        milestone
  2. Understanding the config:

    • The skip list excludes Python versions and Ansible versions that are not available in our environment. This leaves only py3.12 and ansible-core 2.20, keeping the test matrix small and fast.

    • You do not need a tox.ini file — the plugin handles environment creation, dependency installation, and test execution automatically.

    • You do not need to define [testenv:lint] or [testenv:molecule] sections. The plugin creates these for you!

Task 3: Explore the auto-generated environments

Now that the config is updated, let’s see what the plugin found in your project. The --ansible flag activates the plugin and -c tox-ansible.ini tells tox to use our configuration file.

  1. List all available environments:

    tox --ansible -c tox-ansible.ini list

    Observe the magic: Even though your tox-ansible.ini only contains a skip list, the plugin scanned your collection and auto-generated test environments. You should see entries like:

    • galaxy (Build and validate collection artifact)

    • integration-py3.12-2.20 (Auto-discovered molecule scenarios)

    • sanity-py3.12-2.20 (Auto-discovered sanity tests)

    • unit-py3.12-2.20 (Auto-discovered pytest)

      The py3.12 and 2.20 reflect the Python and Ansible versions available in your environment. The plugin automatically matched them based on what is installed and what we did not skip.

Task 4: Run the tests

Now we let tox orchestrate the execution. Remember to always pass --ansible -c tox-ansible.ini so the plugin is activated with the correct config.

  1. Run Sanity Tests:

    tox --ansible -c tox-ansible.ini -e sanity-py3.12-2.20

    Tox creates a virtual environment, installs the required dependencies, and runs ansible-test sanity against your collection. When it finishes, you should see:

      sanity-py3.12-2.20: OK (38.48=setup[4.34]+cmd[28.34,0.02,5.78] seconds)
      congratulations :) (38.58 seconds)
  2. Run Unit Tests:

    tox --ansible -c tox-ansible.ini -e unit-py3.12-2.20

    Expected output:

    tests/unit/test_basic.py::test_basic
    [gw0] [100%] PASSED tests/unit/test_basic.py::test_basic
    
    ============================================================== 1 passed in 0.74s ==============================================================
      unit-py3.12-2.20: OK (32.74=setup[9.41]+cmd[22.03,1.30] seconds)
      congratulations :) (32.84 seconds)
  3. Run Integration Tests (Molecule): Instead of typing the long molecule test -s …​ command, we use the tox environment.

    tox --ansible -c tox-ansible.ini -e integration-py3.12-2.20

    Expected output:

    ============================================================= 1 skipped in 0.69s ==============================================================
      integration-py3.12-2.20: OK (32.88=setup[9.27]+cmd[22.34,1.28] seconds)
      congratulations :) (32.98 seconds)
    The 1 skipped result is expected — the scaffolded test_integration.py is a placeholder. The actual integration tests run through Molecule scenarios.

    This automatically: 1. Creates a fresh virtual environment. 2. Installs Ansible Core 2.20. 3. Installs Molecule and its dependencies. 4. Executes the test scenarios.

Task 5: Build and validate the collection

The galaxy environment builds your collection tarball and runs galaxy-importer to validate it.

  1. Run the galaxy environment:

    tox --ansible -c tox-ansible.ini -e galaxy

    Expected output:

    ...ansible-lint run complete
    Collection loading complete
      galaxy: OK (22.00=setup[8.21]+cmd[13.79] seconds)
      congratulations :) (22.10 seconds)

Troubleshooting

"provided environments not found" Make sure you are passing both --ansible and -c tox-ansible.ini. Without --ansible, the plugin does not activate and the auto-generated environments won’t exist.

"No environments matched" If tox --ansible -c tox-ansible.ini list returns no environments: 1. Ensure you are in the directory containing galaxy.yml. 2. Ensure you actually created the tests/unit folder or molecule scenarios in previous modules. The plugin only generates environments for tests that actually exist.

Summary

In this lab, you utilized the tox-ansible plugin to dramatically simplify test automation.

  • Orchestration: You replaced manual pytest, molecule, and ansible-test commands with a unified tox interface.

  • Auto-discovery: You learned how the plugin scans your collection structure and the tox-ansible.ini config to generate the test matrix automatically.

  • Convention over Configuration: You ran sanity, unit, integration, and galaxy validation tests with a single configuration file and no manual environment definitions.

Next steps

With your testing pipeline automated, you are ready to package your work. Click the Next button below to proceed to Lab 3.1 - Creating an Execution Environment with ansible-builder.