Unit Testing Strategy
Relevant source files
The following files were used as context for generating this wiki page:
The unit testing strategy for flext-tap-ldif is built upon a modular architecture that emphasizes strict typing, protocol-based abstractions, and composition over inheritance. It leverages the flext-tests framework to provide a standardized testing environment for the Singer tap, ensuring high-quality data extraction from LDIF (LDAP Data Interchange Format) files.
The strategy encompasses several layers: behavior contracts for public APIs, domain-specific protocols for mocking LDIF data, and specialized test models and utilities. This structure allows for rigorous validation of tap functionality, including stream discovery and record processing, while maintaining low coupling between test components.
Sources: tests/protocols.py:17-30, tests/unit/test_tap.py:10-21, pyproject.toml:236-267
Testing Architecture and Configuration
The project uses pytest as its primary testing runner, configured with specific plugins to ensure code quality and performance. The configuration mandates strict markers and excludes internal test support modules from standard collection to maintain a clean execution environment.
Tooling and Environment
The test environment is defined in pyproject.toml, specifying dependencies such as pytest-cov for coverage, pytest-xdist for parallel execution, and hypothesis for property-based testing.
| Feature | Description |
|---|---|
| Test Runner | pytest >= 8.4 |
| Markers | unit, integration, e2e, docker, slow, performance |
| Typing | Strict mypy and pyright checks |
| Lazy Loading | Tests utilize flext_core.lazy for efficient export management |
Sources: pyproject.toml:68-112, pyproject.toml:236-267, tests/init.py:11-30
Namespace Organization
Testing components are organized into unified namespaces (e.g., p for protocols, t for types, u for utilities) using composition. This pattern allows flext-tap-ldif to extend generic flext-tests functionality without direct inheritance.
Protocol-Driven Mocking
The strategy utilizes typing.Protocol to define contracts for test double (mock) objects. This allows tests to verify interactions with LDIF files and data providers without relying on actual filesystem IO.
TapLdif Test Protocols
Domain-specific protocols are housed under the TapLdif namespace within the test facade.
- MockLdifFile: Defines operations for opening, closing, and reading entries from simulated LDIF files.
- TestLdifDataProvider: Provides test entries, raw file content, and configuration mappings.
- TestLdifAssertion: Standardizes validation logic for LDIF parsing and stream configuration.
Sources: tests/protocols.py:32-90
Data Models and Typing
Strict typing is enforced through specialized test types and Pydantic-based test models. This ensures that test data structures conform to the expected schemas for LDIF processing.
Test Type Definitions
The project defines specific types for mock data and validation results to support static analysis and IDE autocompletion.
| Type | Description |
|---|---|
MockLdifEntry | A mapping representing a single LDIF entry with attributes. |
MockLdifFile | A sequence of MockLdifEntry objects. |
TestLdifValidationResult | Mapping of validation outcomes, errors, and warnings. |
TestLdifParsingResult | JSON mapping containing parsed LDIF structure. |
Sources: tests/typings.py:32-55
Runtime Bootstrap
Tests are initialized using a TestsFlextTapLdifServiceBase which overrides the bootstrap options to use project-specific settings.
Sources: tests/base.py:14-27
Behavior Contracts (Unit Tests)
Unit tests focus on the behavior contract of the FlextTapLdif class, particularly its public API for stream discovery.
Stream Discovery Validation
A core unit test verifies that the tap correctly identifies the ldif_entries stream when provided with a valid configuration.
# tests/unit/test_tap.py:15-21
def test_discover_streams_returns_ldif_entries_stream(self) -> None:
with tempfile.NamedTemporaryFile(suffix=".ldif", delete=False) as tmp_file:
tap = FlextTapLdif(config={"file_path": tmp_file.name})
streams = tap.discover_streams()
tm.that(len(streams), eq=1)
tm.that(streams[0].name, eq="ldif_entries")
Path(tmp_file.name).unlink(missing_ok=True)
Sources: tests/unit/test_tap.py:15-21
Conclusion
The flext-tap-ldif unit testing strategy ensures reliability through a combination of protocol-based mocking, strict typing via composition, and standardized service bases. By separating the test infrastructure (protocols, models, utilities) from the implementation of behavior contracts, the project maintains a maintainable and scalable testing suite capable of validating complex LDIF extraction logic.