In DevOps, an untested script can bring down an entire production cluster. Unit testing ensures your automation logic is correct before it ever touches a real server.
1. Getting Started with pytest
pytest is the most popular testing framework for Python. It's simple, powerful, and requires less boilerplate than the built-in unittest module.
Your First Test
Action:
# content of test_sample.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0Run Command:
pytest test_sample.pyResult:
============================= test session starts =============================
platform linux -- Python 3.10.x, pytest-7.x.x, pluggy-1.x.x
collected 1 item
test_sample.py . [100%]
============================== 1 passed in 0.01s ==============================2. Testing DevOps Logic
Let's test a function that validates a server's configuration.
Action:
# content of test_config.py
import pytest
def validate_config(config):
if "hostname" not in config:
return False
if not (1 <= config.get("port", 0) <= 65535):
return False
return True
def test_valid_config():
conf = {"hostname": "web-01", "port": 80}
assert validate_config(conf) is True
def test_invalid_port():
conf = {"hostname": "web-01", "port": 99999}
assert validate_config(conf) is False
def test_missing_hostname():
conf = {"port": 80}
assert validate_config(conf) is FalseRun Command:
pytest test_config.pyResult:
test_config.py ... [100%]
============================== 3 passed in 0.02s ==============================3. Mocking External Dependencies
DevOps scripts often call external APIs (AWS, GitHub) or run shell commands. You should mock these during unit tests to avoid making real calls.
Action:
# test_deploy.py
from unittest.mock import patch
def check_site_up(url):
import requests
response = requests.get(url)
return response.status_code == 200
@patch('requests.get')
def test_check_site_up(mock_get):
# Setup the mock to return a 200 status code
mock_get.return_value.status_code = 200
assert check_site_up("http://example.com") is True
mock_get.assert_called_once_with("http://example.com")Run Command:
pytest test_deploy.pyResult:
test_deploy.py . [100%]
============================== 1 passed in 0.01s ==============================4. Pytest Fixtures
Fixtures are a way to provide a fixed baseline upon which tests can reliably and repeatedly execute.
Action:
import pytest
@pytest.fixture
def sample_deployment():
return {
"id": "dep-123",
"status": "pending",
"env": "prod"
}
def test_deployment_id(sample_deployment):
assert sample_deployment["id"].startswith("dep-")
def test_deployment_env(sample_deployment):
assert sample_deployment["env"] == "prod"Result:
test_fixtures.py .. [100%]
============================== 2 passed in 0.01s ==============================Summary
- pytest is the preferred framework for DevOps testing.
- Use
assertstatements to check for expected outcomes. - Use
unittest.mockto simulate API calls and shell commands. - Use Fixtures to set up test data and reusable objects.
- Aim for high test coverage in your automation logic.