Testing
QPyth has a comprehensive test suite with 100% code coverage. This document explains how to run tests and write new tests.
Running Tests
Run All Tests
Run with Coverage
This generates an HTML coverage report in htmlcov/index.html.
Run Specific Test File
Run Specific Test
Run Tests Matching Pattern
Run Tests in Parallel
Skip Slow Tests
Run Integration Tests Only
Test Organization
tests/
├── test_bloch_ascii.py # Bloch sphere tests
├── test_bloch_ascii_run.py # Bloch ASCII runner tests
├── test_circuit_explorer.py # Circuit explorer tests
├── test_config.py # Configuration tests
├── test_decoherence_toggle.py # Decoherence tests
├── test_hardware_ibm.py # IBM hardware tests
├── test_main.py # Main module tests
├── test_menu.py # CLI menu tests
├── test_qec_shor.py # Shor code tests
├── test_qec_steane.py # Steane code tests
├── test_qrng_sacred.py # QRNG tests
├── test_smoke.py # Smoke tests
├── test_teleport_bridge.py # Teleportation tests
├── test_tmt_sierpinski.py # Sierpinski tests
├── test_vqe_core.py # VQE core tests
├── test_vqe_h2.py # H2 VQE tests
├── test_vqe_h2_cli.py # H2 VQE CLI tests
├── test_vqe_h2_exact.py # H2 VQE exact tests
├── test_vqe_h2_extra.py # H2 VQE extra tests
├── test_vqe_molecules.py # Molecule tests
└── test_vqe_utils.py # VQE utility tests
Writing Tests
Basic Test Structure
import pytest
from quantumpytho.modules.bloch_ascii import run_bloch_ascii
def test_run_bloch_ascii_zero_state(capsys):
"""Test Bloch visualization for |0⟩ state."""
run_bloch_ascii(theta=0, phi=0)
captured = capsys.readouterr()
assert "|0> state:" in captured.out
assert "100.00%" in captured.out
Using Fixtures
import pytest
from qiskit import QuantumCircuit
@pytest.fixture
def bell_circuit():
"""Create a Bell pair circuit."""
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
return qc
def test_bell_circuit_structure(bell_circuit):
"""Test Bell circuit has correct structure."""
assert bell_circuit.num_qubits == 2
assert bell_circuit.depth() == 2
Mocking External Dependencies
import pytest
from unittest.mock import Mock, patch
from quantumpytho.modules.hardware_ibm import IBMHardwareEngine
def test_connect_with_mock():
"""Test connection with mocked IBM service."""
with patch('quantumpytho.modules.hardware_ibm.QiskitRuntimeService') as mock_service:
mock_instance = Mock()
mock_service.return_value = mock_instance
engine = IBMHardwareEngine()
engine.connect()
mock_service.assert_called_once()
Parameterized Tests
import pytest
@pytest.mark.parametrize("theta,phi,expected", [
(0, 0, "|0⟩"),
(3.14159, 0, "|1⟩"),
(1.5708, 0, "|+⟩"),
])
def test_bloch_states(theta, phi, expected):
"""Test various Bloch sphere states."""
from quantumpytho.modules.bloch_ascii import run_bloch_ascii
run_bloch_ascii(theta=theta, phi=phi)
# Assert expected behavior
Testing Exceptions
import pytest
def test_invalid_input_raises_error():
"""Test that invalid input raises appropriate error."""
from quantumpytho.modules.bloch_ascii import run_bloch_ascii
with pytest.raises(ValueError):
run_bloch_ascii(theta=10, phi=0) # Invalid theta
Testing Async Code
import pytest
import asyncio
@pytest.mark.asyncio
async def test_async_function():
"""Test async function."""
result = await async_function()
assert result is not None
Test Markers
QPyth uses pytest markers for test categorization. These markers help organize tests and allow selective execution, which is particularly useful for CI pipelines.
Available Markers
@pytest.mark.slow
def test_slow_operation():
"""Test that takes a long time (e.g., quantum simulation with many shots)."""
pass
@pytest.mark.integration
def test_hardware_integration():
"""Test that requires hardware access."""
pass
Slow Tests
The @pytest.mark.slow marker is used for tests that take longer to execute,
typically those involving quantum simulations with many shots or complex circuits:
@pytest.mark.slow
def test_teleport_measurement_distribution():
"""Test teleportation measurement distribution (slow test)."""
qc = build_teleport_circuit()
backend = AerSimulator()
job = backend.run(qc, shots=1000)
result = job.result()
counts = result.get_counts(qc)
assert len(counts) > 0
Current slow tests include:
- test_bloch_ascii.py::test_bloch_ascii_run - ASCII visualization tests
- test_qec_shor.py::test_shor_qec_demo - Shor code error correction
- test_qec_steane.py::test_steane_qec_demo - Steane code error correction
- test_teleport_bridge.py::test_teleport_measurement_distribution - Teleportation
- test_vqe_h2.py::test_vqe_h2 - VQE molecular simulation
- test_qrng_sacred.py::test_qrng_sacred - Quantum random number generation
Running Specific Markers
Run only slow tests:
Skip slow tests (useful for quick feedback):
Run integration tests:
Run all tests except slow ones:
CI Configuration
In CI pipelines, it's good practice to:
-
Run fast tests first for quick feedback:
-
Run slow tests separately (can be in a parallel job):
-
Combine coverage from both runs for complete reporting
This approach allows developers to get quick feedback on most changes while ensuring comprehensive testing before merging.
Coverage Goals
QPyth maintains 100% code coverage. To check coverage:
This shows which lines are not covered by tests.
Continuous Integration
Tests run automatically on GitHub Actions for every push and pull request. The CI pipeline:
- Runs all tests
- Checks code coverage (must be 100%)
- Runs linter (ruff)
- Checks code formatting
Debugging Tests
Run Tests in Debug Mode
This drops into pdb on failure.
Print Output
This shows print statements.
Verbose Output
This shows detailed test information.
Stop on First Failure
Best Practices
- Test Isolation - Each test should be independent
- Descriptive Names - Use clear, descriptive test names
- Arrange-Act-Assert - Structure tests clearly
- Mock External Dependencies - Don't rely on external services
- Test Edge Cases - Test boundary conditions and error cases
- Keep Tests Fast - Use markers for slow tests
- Use Fixtures - Reuse common setup code
- Test Public API - Focus on public interfaces, not implementation details
Example Test Suite
import pytest
from quantumpytho.modules.bloch_ascii import run_bloch_ascii
class TestBlochAscii:
"""Test suite for Bloch ASCII visualization."""
def test_zero_state(self, capsys):
"""Test |0⟩ state visualization."""
run_bloch_ascii(theta=0, phi=0)
captured = capsys.readouterr()
assert "|0> state:" in captured.out
assert "100.00%" in captured.out
def test_one_state(self, capsys):
"""Test |1⟩ state visualization."""
run_bloch_ascii(theta=3.14159, phi=0)
captured = capsys.readouterr()
assert "|1> state:" in captured.out
assert "100.00%" in captured.out
def test_plus_state(self, capsys):
"""Test |+⟩ state visualization."""
run_bloch_ascii(theta=1.5708, phi=0)
captured = capsys.readouterr()
assert "|0> state:" in captured.out
assert "|1> state:" in captured.out
@pytest.mark.parametrize("theta,phi", [
(0, 0),
(3.14159, 0),
(1.5708, 0),
(1.5708, 1.5708),
])
def test_various_states(self, theta, phi, capsys):
"""Test various quantum states."""
run_bloch_ascii(theta=theta, phi=phi)
captured = capsys.readouterr()
assert "State Vector Projection" in captured.out
def test_invalid_theta_raises_error(self):
"""Test that invalid theta raises error."""
with pytest.raises(ValueError):
run_bloch_ascii(theta=10, phi=0)
Troubleshooting
Import Errors
If you get import errors:
Missing Dependencies
If tests fail due to missing dependencies:
Coverage Not 100%
If coverage is not 100%:
- Run coverage report:
pytest --cov=quantumpytho --cov-report=html - Open
htmlcov/index.htmlin browser - Find uncovered lines
- Write tests for uncovered code
Tests Failing Randomly
If tests are flaky:
- Check for external dependencies
- Mock external services
- Use deterministic random seeds
- Check for race conditions
Resources
Next Steps
- Contributing - Learn how to contribute
- Architecture - Understand project architecture
- API Reference - Complete API documentation