Testing Guide¶
This guide covers testing practices and procedures for LeeQ development.
Test Structure¶
LeeQ uses pytest for testing, with tests organized as follows:
tests/
├── unit/ # Unit tests for individual components
│ ├── core/ # Core module tests
│ ├── experiments/ # Experiment tests
│ └── utils/ # Utility tests
├── integration/ # Integration tests
└── fixtures/ # Shared test fixtures
Running Tests¶
Basic Test Execution¶
# Run all tests
pytest
# Run with verbose output
pytest -v
# Run specific test file
pytest tests/unit/core/test_elements.py
# Run specific test
pytest tests/unit/core/test_elements.py::test_qubit_initialization
Test Coverage¶
# Run with coverage report
pytest --cov=leeq
# Generate HTML coverage report
pytest --cov=leeq --cov-report=html
# View coverage report
open htmlcov/index.html
Test Categories¶
# Run only unit tests
pytest tests/unit/
# Run only integration tests
pytest tests/integration/
# Run tests matching pattern
pytest -k "rabi"
Writing Tests¶
Unit Test Example¶
import pytest
from leeq.core.elements import Qubit
def test_qubit_frequency():
"""Test qubit frequency setting."""
qubit = Qubit(name="q0")
qubit.set_frequency(5.0e9)
assert qubit.frequency == 5.0e9
def test_qubit_invalid_frequency():
"""Test invalid frequency raises error."""
qubit = Qubit(name="q0")
with pytest.raises(ValueError):
qubit.set_frequency(-1.0)
Integration Test Example¶
import pytest
from leeq.experiments import RabiExperiment
from leeq.setups import create_virtual_setup
@pytest.fixture
def virtual_setup():
"""Create virtual setup for testing."""
return create_virtual_setup(num_qubits=2)
def test_rabi_experiment_workflow(virtual_setup):
"""Test complete Rabi experiment workflow."""
qubit = virtual_setup.get_qubit(0)
experiment = RabiExperiment(
qubit=qubit,
amplitude_range=(0, 1),
num_points=20
)
result = experiment.run()
assert result.success
assert result.optimal_amplitude is not None
Test Fixtures¶
Common Fixtures¶
Located in tests/fixtures/:
# conftest.py
import pytest
from leeq.core.elements import Qubit
@pytest.fixture
def sample_qubit():
"""Provide a sample qubit for testing."""
return Qubit(
name="test_qubit",
frequency=5.0e9,
anharmonicity=-200e6
)
@pytest.fixture
def mock_hardware():
"""Mock hardware interface."""
from unittest.mock import Mock
hardware = Mock()
hardware.execute.return_value = {"success": True}
return hardware
Mocking and Patching¶
Mocking Hardware¶
from unittest.mock import patch, Mock
@patch('leeq.hardware.quantum_device')
def test_with_mock_hardware(mock_device):
"""Test with mocked hardware."""
mock_device.execute.return_value = {
"counts": {"0": 500, "1": 500}
}
# Your test code here
result = run_experiment()
assert mock_device.execute.called
Test Best Practices¶
1. Test Organization¶
- One test file per module
- Group related tests in classes
- Use descriptive test names
2. Test Independence¶
- Tests should not depend on each other
- Clean up resources after tests
- Use fixtures for shared setup
3. Assertions¶
- Use specific assertions
- Test both success and failure cases
- Include edge cases
4. Documentation¶
- Add docstrings to test functions
- Explain complex test scenarios
- Document expected behaviors
Continuous Integration¶
Tests run automatically on: - Pull requests - Commits to main branch - Nightly builds
Environment Setup for CI¶
Critical environment variables for headless testing:
export MPLBACKEND=Agg
export PYTHONDONTWRITEBYTECODE=1
export QT_QPA_PLATFORM=offscreen
Current CI Configuration¶
The project uses GitHub Actions with configurations in .github/workflows/.
Performance Testing¶
Benchmarking¶
import pytest
import time
@pytest.mark.benchmark
def test_performance():
"""Benchmark critical operations."""
start = time.time()
# Operation to benchmark
result = expensive_operation()
duration = time.time() - start
assert duration < 1.0 # Should complete in under 1 second
Debugging Tests¶
Running with debugger¶
# Run with pdb on failure
pytest --pdb
# Run with verbose traceback
pytest --tb=long
# Run with print statements visible
pytest -s
Using pytest markers¶
@pytest.mark.slow
def test_slow_operation():
"""Mark slow tests."""
pass
# Run excluding slow tests
pytest -m "not slow"
Test Data¶
Store test data in tests/data/:
- Sample configuration files
- Expected output files
- Mock response data
import os
import json
def test_with_data():
"""Test using external data file."""
data_path = os.path.join(
os.path.dirname(__file__),
"data",
"sample_results.json"
)
with open(data_path) as f:
expected = json.load(f)
result = process_data()
assert result == expected