Testing Philosophy & Contract Tests
Relevant source files
The following files were used as context for generating this wiki page:
ProxyBroker2 employs a comprehensive, contract-based testing strategy to ensure reliability while allowing for internal implementation flexibility. This approach focuses on verifying user-visible behavior and stable public APIs rather than internal algorithms or private attributes. By validating the "what" instead of the "how," the test suite protects the project from breaking changes during refactors and upgrades to modern Python versions.
The testing architecture is categorized into unit tests for component initialization, integration tests for end-to-end workflows, and specific contract tests that lock in public API signatures. This strategy supports the project's goal of being production-ready by catching regressions in critical paths such as proxy finding, validation, and server rotation.
Sources: README.md:214-232, CLAUDE.md:154-162, tests/README.md:1-10
Core Testing Principles
The testing philosophy prioritizes the stability of public interfaces and the correctness of high-level outcomes. Developers must focus on the following pillars when writing or maintaining tests:
- Test Behavior, Not Implementation: Verify that a method produces the correct output for a given input, not which internal private methods it calls.
- Focus on User-Visible Outcomes: Ensure that core features like proxy discovery and anonymity detection work as expected from a user's perspective.
- Stable API Signatures: Maintain consistent method parameters and return types to prevent breaking downstream consumer code.
- Flexible Internals: Allow internal algorithms, like heap management or protocol parsing, to evolve without requiring test updates, provided the public contract remains intact.
Sources: CLAUDE.md:154-162, README.md:218-226
Contract vs. Implementation Testing
| Category | What We Test (Stable Contracts) | What We Avoid (Internal Details) |
|---|---|---|
| API | Function signatures, default parameters, and return types. | Private attributes (prefixed with _) and internal helper calls. |
| Data | JSON/Text output formats and required data fields. | Internal data structure representation or storage order. |
| Behavior | Success/failure outcomes and specific exception types. | Exact sequence of internal async tasks or local variables. |
| Protocols | Support for HTTP, HTTPS, SOCKS4/5. | Exact byte-level protocol implementation details. |
Sources: README.md:218-226, CLAUDE.md:154-162, tests/test_public_contracts.py:10-15
Contract Test Architecture
Contract tests ensure that the public interfaces of key classes remain stable. These tests use the inspect module to validate signatures and verify that mandatory methods exist.
The diagram shows how contract tests target specific initialization and operational interfaces across core components.
Sources: tests/test_public_contracts.py:20-25, tests/test_api.py:10-15
Broker Contract Specifications
The Broker class must maintain a stable set of parameters in its constructor and core methods.
- Constructor: Must accept
queue,timeout,max_conn,max_tries,judges,providers,verify_ssl, andprovider_dirs. - find(): An asynchronous method accepting
types,limit, and filtering kwargs. - grab(): An asynchronous method for finding proxies without validation, accepting
countriesandlimit. - serve(): A method to initialize the proxy server, accepting
host,port, andlimit.
Sources: tests/test_public_contracts.py:23-74, tests/test_api.py:21-45
Proxy Data Contracts
The Proxy object acts as the primary data carrier. Its output formats are strictly enforced:
- as_json(): Must return a dictionary containing
host,port,geo,types,avg_resp_time, anderror_rate. - as_text(): Must return a string in the
host:port\nformat. - IPv6 Bracketing: IPv6 addresses in text output must be bracketed (e.g.,
[2001:db8::1]:8080) per RFC 3986.
Sources: tests/test_public_contracts.py:102-145, CHANGELOG.md:28-32
Integration and Workflow Testing
Integration tests simulate real-world usage patterns found in the project's examples. They verify that components like the Broker, Checker, and ProxyPool interact correctly.
This sequence represents the standard "Find and Use" workflow verified by integration tests.
Sources: tests/test_integration.py:15-60, tests/README.md:46-55
Critical Business Logic Validation
- ProxyPool Heap Management: Tests verify that the pool maintains correct ordering by
avg_resp_timeand that "bad" proxies are discarded based on error rate or response time thresholds. - Anonymity Detection: The
Checkeris tested against mock responses to ensure correct classification (Transparent, Anonymous, High) based on leaked headers likeViaandX-Forwarded-For. - IPv6 Support: Tests ensure that IPv6 addresses are canonicalized using RFC 5952 to prevent duplicate entries and ensure correct anonymity comparison.
Sources: tests/README.md:61-75, CHANGELOG.md:20-45, tests/test_checker.py:134-165
Error Handling Contracts
The test suite enforces an exception hierarchy that users rely on for robust error management.
| Exception Class | Purpose | Parent Class |
|---|---|---|
ProxyError | Base class for all proxy-related issues. | Exception |
NoProxyError | Raised when the ProxyPool is empty and no proxies meet criteria. | Exception |
ProxyTimeoutError | Raised when a proxy connection or request times out. | ProxyError |
ResolveError | Raised when DNS resolution fails for a proxy host. | Exception |
ProxyConnError | Raised when a connection to a proxy fails. | ProxyError |
Sources: tests/test_public_contracts.py:228-255, tests/test_integration.py:228-240
Mocking and Infrastructure
To maintain test isolation and speed, ProxyBroker2 uses specific mock infrastructure:
- MockJudgeServer: Simulates judge responses to test anonymity detection without real network calls.
- MockProviderServer: Returns static proxy lists in various formats (HTML, Text, JSON) to test provider parsers.
- Mock Factories: Utilities like
create_mock_proxy()generate consistent test data with realistic attributes.
Sources: tests/README.md:83-93, tests/test_server.py:25-35
Execution Guidelines
Tests are executed using pytest with asyncio support. The environment is configured in pyproject.toml.
# Run all tests
poetry run pytest tests/ -v
# Check coverage
poetry run pytest tests/ --cov=proxybroker --cov-report=term-missing
# Run specific component tests
poetry run pytest tests/test_public_contracts.py -v
Sources: tests/README.md:95-115, CLAUDE.md:28-40, pyproject.toml:98-100
Testing Philosophy in ProxyBroker2 ensures that the system remains reliable across major updates, such as the transition from Python 3.5 to 3.14 and the addition of first-class IPv6 support. By focusing on public contracts, the project provides a stable foundation for production-grade async proxy management.