Files
wehub-resource-sync fbfefa28d3
CodeQL / Analyze (python) (push) Failing after 0s
Release / Build (push) Failing after 1s
Test Suite / Unit Tests (push) Failing after 0s
Release / Release (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:18:10 +08:00

431 lines
9.8 KiB
Markdown

# ScrapeGraphAI Testing Infrastructure
Comprehensive testing infrastructure for ScrapeGraphAI with support for unit tests, integration tests, and performance benchmarks.
## Table of Contents
- [Overview](#overview)
- [Test Organization](#test-organization)
- [Running Tests](#running-tests)
- [Test Fixtures](#test-fixtures)
- [Performance Benchmarking](#performance-benchmarking)
- [Mock Server](#mock-server)
- [CI/CD Integration](#cicd-integration)
## Overview
The testing infrastructure includes:
- **Unit Tests**: Fast, isolated tests with mocked dependencies
- **Integration Tests**: Tests with real LLM providers and websites
- **Performance Benchmarks**: Track performance metrics and detect regressions
- **Mock HTTP Server**: Consistent testing without external dependencies
- **Multi-Provider Support**: Test compatibility across different LLM providers
## Test Organization
```
tests/
├── conftest.py # Shared fixtures and pytest configuration
├── pytest.ini # Pytest settings (in project root)
├── fixtures/
│ ├── mock_server/ # Mock HTTP server for testing
│ │ ├── __init__.py
│ │ └── server.py
│ ├── benchmarking.py # Performance benchmarking utilities
│ ├── helpers.py # Test utilities and helpers
│ ├── data/ # Test data files
│ └── html/ # HTML fixtures
├── integration/ # Integration tests
│ ├── test_smart_scraper_integration.py
│ ├── test_multi_graph_integration.py
│ └── test_file_formats_integration.py
├── graphs/ # Graph-specific tests
├── nodes/ # Node-specific tests
└── utils/ # Utility tests
```
## Running Tests
### All Tests
```bash
pytest
```
### Unit Tests Only
```bash
pytest -m "unit or not integration"
```
### Integration Tests
```bash
pytest --integration
```
### With Coverage
```bash
pytest --cov=scrapegraphai --cov-report=html
```
### Performance Benchmarks
```bash
pytest --benchmark -m benchmark
```
### Slow Tests
```bash
pytest --slow
```
### Specific Test File
```bash
pytest tests/integration/test_smart_scraper_integration.py
```
### Verbose Output
```bash
pytest -v
```
## Test Fixtures
### LLM Provider Fixtures
Pre-configured fixtures for all supported LLM providers:
```python
def test_with_openai(openai_config):
"""Use OpenAI configuration."""
scraper = SmartScraperGraph(
prompt="...",
source="...",
config=openai_config
)
```
Available fixtures:
- `openai_config` - OpenAI GPT-3.5
- `openai_gpt4_config` - OpenAI GPT-4
- `ollama_config` - Ollama (local)
- `anthropic_config` - Anthropic Claude
- `groq_config` - Groq
- `azure_config` - Azure OpenAI
- `gemini_config` - Google Gemini
### Mock LLM Fixtures
For unit testing without API calls:
```python
def test_with_mock_llm(mock_llm_model, mock_embedder_model):
"""Use mocked LLM for fast unit tests."""
# Test logic here
```
### File Fixtures
Temporary files for testing:
```python
def test_json_scraping(temp_json_file):
"""Use temporary JSON file."""
scraper = JSONScraperGraph(
prompt="...",
source=temp_json_file,
config=config
)
```
Available fixtures:
- `temp_json_file`
- `temp_html_file`
- `temp_xml_file`
- `temp_csv_file`
### Mock HTTP Server
Local HTTP server for consistent testing:
```python
def test_with_mock_server(mock_server):
"""Use mock HTTP server."""
url = mock_server.get_url("/products")
scraper = SmartScraperGraph(
prompt="Extract products",
source=url,
config=config
)
```
Available endpoints:
- `/` - Home page
- `/products` - Products listing
- `/projects` - Projects listing
- `/api/data.json` - JSON endpoint
- `/api/data.xml` - XML endpoint
- `/api/data.csv` - CSV endpoint
- `/slow` - Slow response (2s delay)
- `/error/404` - 404 error
- `/error/500` - 500 error
- `/rate-limited` - Rate limiting simulation
- `/pagination?page=N` - Paginated content
## Performance Benchmarking
### Using the Benchmark Tracker
```python
def test_performance(benchmark_tracker):
"""Track performance metrics."""
import time
start = time.perf_counter()
# ... run scraping ...
end = time.perf_counter()
from tests.fixtures.benchmarking import BenchmarkResult
result = BenchmarkResult(
test_name="my_test",
execution_time=end - start,
token_usage=1000,
api_calls=2,
success=True
)
benchmark_tracker.record(result)
```
### Generating Reports
After running benchmarks:
```python
# In your test or conftest.py
tracker.save_results()
report = tracker.generate_report()
print(report)
```
### Comparing Against Baseline
```bash
# Save baseline
pytest --benchmark -m benchmark
cp benchmark_results/benchmark_results.json baseline.json
# Run tests and compare
pytest --benchmark -m benchmark
# Compare programmatically
from tests.fixtures.benchmarking import pytest_benchmark_compare
comparison = pytest_benchmark_compare(
Path("baseline.json"),
Path("benchmark_results/benchmark_results.json")
)
```
## Test Markers
### Available Markers
- `@pytest.mark.unit` - Unit tests (fast, no external deps)
- `@pytest.mark.integration` - Integration tests (require network)
- `@pytest.mark.slow` - Slow-running tests
- `@pytest.mark.benchmark` - Performance benchmarks
- `@pytest.mark.requires_api_key` - Tests requiring API keys
- `@pytest.mark.llm_provider(name)` - Tests for specific LLM provider
### Usage Example
```python
@pytest.mark.integration
@pytest.mark.requires_api_key
@pytest.mark.slow
def test_comprehensive_scraping(openai_config):
"""This test requires API keys and network access."""
# Test implementation
```
## Environment Variables
Set these environment variables for integration tests:
```bash
# LLM API Keys
export OPENAI_APIKEY="sk-..."
export ANTHROPIC_APIKEY="sk-ant-..."
export GROQ_APIKEY="gsk_..."
export GEMINI_APIKEY="..."
# Azure OpenAI
export AZURE_OPENAI_KEY="..."
export AZURE_OPENAI_ENDPOINT="https://..."
# Test Configuration
export TEST_WEBSITE_URL="https://scrapegrah-ai-website-for-tests.onrender.com"
export OLLAMA_BASE_URL="http://localhost:11434"
```
## CI/CD Integration
### GitHub Actions
The test suite runs automatically on:
- Push to main, pre/beta, dev branches
- Pull requests
- Daily scheduled runs
- Manual workflow dispatch
### Test Jobs
1. **Unit Tests**: Run on multiple OS and Python versions
2. **Integration Tests**: Test with real LLM providers
3. **Performance Benchmarks**: Track performance metrics
4. **Code Quality**: Linting, formatting, type checking
### Viewing Results
- Test results are uploaded as artifacts
- Coverage reports are sent to Codecov
- Performance benchmarks are saved for comparison
## Writing New Tests
### Unit Test Template
```python
import pytest
from unittest.mock import Mock, patch
class TestMyFeature:
@pytest.fixture
def setup(self):
"""Setup fixture for tests."""
return {"data": "value"}
def test_my_function(self, setup, mock_llm_model):
"""Test description."""
# Arrange
# Act
# Assert
```
### Integration Test Template
```python
import pytest
from scrapegraphai.graphs import SmartScraperGraph
@pytest.mark.integration
@pytest.mark.requires_api_key
class TestMyIntegration:
def test_real_scraping(self, openai_config, mock_server):
"""Test with real LLM provider."""
url = mock_server.get_url("/test-page")
scraper = SmartScraperGraph(
prompt="Extract data",
source=url,
config=openai_config
)
result = scraper.run()
assert result is not None
assert isinstance(result, dict)
```
### Benchmark Test Template
```python
import pytest
import time
from tests.fixtures.benchmarking import BenchmarkResult
@pytest.mark.benchmark
class TestMyBenchmark:
def test_performance(self, benchmark_tracker, openai_config):
"""Benchmark test description."""
start = time.perf_counter()
# Run operation to benchmark
end = time.perf_counter()
result = BenchmarkResult(
test_name="my_benchmark",
execution_time=end - start,
success=True
)
benchmark_tracker.record(result)
```
## Troubleshooting
### Tests Timeout
Increase timeout in pytest.ini or per-test:
```python
@pytest.mark.timeout(120) # 2 minutes
def test_long_running():
pass
```
### API Rate Limits
Use mock server or implement rate limiting in tests:
```python
from tests.fixtures.helpers import RateLimitHelper
rate_limiter = RateLimitHelper(max_requests=5, time_window=60)
```
### Flaky Tests
Mark tests as flaky and allow retries:
```python
@pytest.mark.flaky(reruns=3, reruns_delay=2)
def test_sometimes_fails():
pass
```
## Best Practices
1. **Use appropriate markers** - Mark tests correctly for proper filtering
2. **Mock external dependencies** - Use mock server and fixtures
3. **Test isolation** - Each test should be independent
4. **Clear assertions** - Use helper functions for better error messages
5. **Performance tracking** - Use benchmarking for critical paths
6. **Documentation** - Document test purpose and requirements
7. **Cleanup** - Use fixtures and context managers for proper cleanup
## Contributing
When adding tests:
1. Follow existing test structure and naming conventions
2. Add appropriate markers
3. Document test requirements (API keys, network, etc.)
4. Update this README if adding new test infrastructure
5. Ensure tests pass in CI before submitting PR
## Additional Resources
- [pytest Documentation](https://docs.pytest.org/)
- [pytest-cov Documentation](https://pytest-cov.readthedocs.io/)
- [ScrapeGraphAI Documentation](https://docs.scrapegraphai.com/introduction)