Testing¶
This guide describes the test suite for azure-functions-validation, including how to run tests, the structure of the test suite, and guidelines for contributing new tests.
Overview¶
The azure-functions-validation project maintains a high standard of quality through a comprehensive test suite. The suite ensures that request validation, response serialization, and decorator behavior work correctly across different Python versions and Azure Functions scenarios.
- Total Tests: 145+
- Code Coverage: 99%
- Supported Environments: Python 3.10, 3.11, 3.12, 3.13, and 3.14
The test suite covers unit tests for individual modules, integration tests with real Azure Function handlers, and smoke tests using the provided examples.
Running Tests¶
The project uses pytest as its primary testing framework. You can run the tests using make targets or directly via hatch.
Using Makefile¶
The simplest way to run tests is using the provided Makefile targets:
The make cov command generates a terminal report, an XML report for CI integration, and a detailed HTML report in the htmlcov/ directory.
Direct Commands¶
If you prefer to run commands manually via hatch:
To pass specific arguments to pytest (e.g., to run a single test file):
Test Structure¶
Tests are located in the tests/ directory and organized by the functional area they cover:
| File | Description |
|---|---|
test_decorator.py |
Validates configuration-time errors when applying @validate_http. |
test_pipeline.py |
Tests the runtime behavior including parsing, validation, and response building. |
test_errors.py |
Focuses on the error module and default error formatting logic. |
test_integration.py |
End-to-end tests using real Azure Function handlers and request objects. |
test_examples.py |
Smoke tests that verify the code snippets in the examples/ directory. |
test_public_api.py |
Verifies the public API surface and export stability. |
test_adapter.py |
Tests the adapter layer responsible for interacting with Azure Functions types. |
test_placeholder.py |
Minimal sanity check for the test environment. |
The tests/_test_app/ directory contains a sample Azure Functions application used by the integration tests to verify decorator behavior in a realistic environment.
Test Organization¶
Tests are generally organized into classes to group related functionality and share logic. Common patterns include:
TestSuccessfulValidation: Verifies that valid requests result in successful processing and correct responses.TestValidationErrors: Verifies that invalid input (body, query, path, headers) results in the expected 422 Unprocessable Entity responses.TestAsyncHandlers: Ensures that both synchronous and asynchronous Azure Function handlers are supported correctly.TestCustomErrorFormatter: Validates that users can override the default error response format.TestConfigurationErrors: Checks that improper use of the decorator (e.g., conflicting parameters) is caught at decoration time.
Fixtures¶
The project uses pytest fixtures to simplify test setup. The most important fixture is mock_request_factory.
mock_request_factory¶
Located in tests/test_pipeline.py, this fixture provides a factory function to create mock azure.functions.HttpRequest objects. It allows you to specify the method, URL, body, and various parameters without manually setting up complex mock objects.
def test_example(mock_request_factory):
request = mock_request_factory(
method="POST",
body=b'{"name": "Alice"}',
params={"debug": "true"}
)
# Use the mock request in your test
Integration Test Patterns¶
MockHttpRequest Class¶
For tests that require a more robust representation of a request than a simple unittest.mock.Mock, the tests/test_integration.py file defines a MockHttpRequest class. This class implements the HttpRequest interface, providing realistic behavior for methods like get_json() and get_body().
This is particularly useful when testing how the validation layer interacts with the internal state of an Azure Functions request object.
Writing New Tests¶
When contributing new features or fixing bugs, please follow these guidelines:
- Location: Place unit tests in the file corresponding to the module being tested. If it's a new functional area, create a new
test_*.pyfile. - Naming: Use descriptive names for test functions, starting with
test_. Use class-based grouping for related tests. - Mocking: Use the
mock_request_factoryfor unit tests. For integration tests that need to verify handler behavior, refer to the patterns intest_integration.py. - Async: If testing async functionality, mark the test with
@pytest.mark.anyio.
Example of a new test:
@pytest.mark.anyio
async def test_my_new_feature(mock_request_factory):
@validate_http(body=MyModel)
async def handler(req, body):
return {"result": body.value}
request = mock_request_factory(body=b'{"value": 42}')
response = await handler(request)
assert response.status_code == 200
Coverage Configuration¶
Coverage settings are defined in pyproject.toml. The project tracks branch coverage to ensure all logical paths are exercised.
- Source:
src/azure_functions_validation - Reports: Terminal (missing lines), XML (for CI), and HTML.
- Branch Coverage: Enabled (
branch = true).
You can view the coverage configuration under the [tool.coverage.run] and [tool.coverage.report] sections of pyproject.toml.
CI Test Matrix¶
The test suite runs automatically on every pull request and push to the main branch. The CI matrix ensures compatibility across:
- OS:
ubuntu-latest - Python Versions: 3.10, 3.11, 3.12, 3.13, 3.14
This is managed via the .github/workflows/ci-test.yml configuration.
Troubleshooting¶
Common Test Failures¶
- PYTHONPATH Issues: If tests cannot find the
srcorexamplesmodules, ensure your environment is set up correctly. Running viahatch run testormake testhandles this automatically via thepythonpathsetting inpyproject.toml. - Pydantic Version: The project supports Pydantic v2. Tests may fail if an older version of Pydantic is installed.
- Async Setup: Ensure
pytest-anyiois installed and tests are correctly marked with@pytest.mark.anyio. - Missing Dependencies: If you see import errors for
azure.functions, ensure you have installed the development dependencies usingpip install -e .[dev].