Integration Testing in Ansible
Overview
Integration testing verifies that multiple components of your Ansible automation work together correctly. This includes testing playbooks, roles, and their interactions with the target systems.
Test Structure
Directory Layout
integration_tests/
├── inventory/
│ ├── group_vars/
│ │ └── all.yml
│ └── hosts
├── roles/
│ └── role_under_test/
├── playbooks/
│ ├── test_playbook.yml
│ └── verify_playbook.yml
└── pytest.ini
Example Integration Tests
Test Inventory
# inventory/hosts
[webservers]
webserver1 ansible_host=localhost ansible_connection=docker
webserver2 ansible_host=localhost ansible_connection=docker
[databases]
db1 ansible_host=localhost ansible_connection=docker
Test Playbook
# playbooks/test_playbook.yml
---
- name: Test web server setup
hosts: webservers
roles:
- role: nginx_role
- role: php_role
tasks:
- name: Verify nginx installation
ansible.builtin.service:
name: nginx
state: started
register: nginx_status
- name: Verify PHP installation
ansible.builtin.command: php --version
register: php_version
changed_when: false
- name: Test database setup
hosts: databases
roles:
- role: mysql_role
tasks:
- name: Verify MySQL installation
ansible.builtin.service:
name: mysql
state: started
register: mysql_status
Verification Playbook
# playbooks/verify_playbook.yml
---
- name: Verify web stack
hosts: webservers
tasks:
- name: Check nginx configuration
ansible.builtin.stat:
path: /etc/nginx/sites-enabled/default
register: nginx_config
- name: Test nginx response
ansible.builtin.uri:
url: http://localhost
return_content: yes
register: webpage
until: webpage.status == 200
retries: 3
delay: 5
- name: Verify PHP functionality
ansible.builtin.shell: |
echo "<?php phpinfo(); ?>" > /var/www/html/info.php
curl -s http://localhost/info.php | grep -i "PHP Version"
register: php_info
changed_when: false
- name: Verify database
hosts: databases
tasks:
- name: Check MySQL connection
ansible.builtin.command: mysqladmin ping
register: mysql_ping
changed_when: false
Running Integration Tests
Using pytest-ansible
# test_integration.py
import pytest
from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager
from ansible.vars.manager import VariableManager
from ansible.executor.playbook_executor import PlaybookExecutor
def test_playbook_execution(ansible_runner):
result = ansible_runner.run(
playbook='playbooks/test_playbook.yml',
inventory='inventory/hosts'
)
assert result.rc == 0
def test_nginx_installation(ansible_adhoc):
result = ansible_adhoc.command('nginx -v')
assert result.is_successful
def test_mysql_connection(ansible_adhoc):
result = ansible_adhoc.shell('mysql -e "SELECT VERSION();"')
assert result.is_successful
Infrastructure Testing
Using Testinfra
# test_infrastructure.py
def test_nginx_is_installed(host):
nginx = host.package("nginx")
assert nginx.is_installed
assert nginx.version.startswith("1.18")
def test_nginx_is_running(host):
nginx = host.service("nginx")
assert nginx.is_running
assert nginx.is_enabled
def test_ports_are_listening(host):
assert host.socket("tcp://0.0.0.0:80").is_listening
def test_php_config(host):
php_config = host.file("/etc/php/7.4/fpm/php.ini")
assert php_config.exists
assert php_config.contains("memory_limit = 256M")
CI/CD Integration Example
# .github/workflows/integration-tests.yml
name: Integration Tests
on: [push, pull_request]
jobs:
integration-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install ansible pytest pytest-ansible testinfra docker
- name: Start test containers
run: |
docker-compose -f tests/docker-compose.yml up -d
- name: Run integration tests
run: |
pytest tests/integration/ -v
- name: Run infrastructure tests
run: |
pytest tests/infrastructure/ -v --connection=docker
Best Practices
- Environment Isolation
- Use containers or VMs for testing
- Reset environment between tests
-
Use appropriate wait conditions
-
Test Coverage
- Test all major configuration changes
- Verify service states
- Check actual functionality
-
Test failure scenarios
-
CI/CD Integration
- Automate test execution
- Maintain test environments
- Archive test results
-
Set up notifications
-
Performance Considerations
- Use parallel testing where possible
- Implement test timeouts
- Cache dependencies
- Clean up test resources