Fixtures Reference

pytest-quantum provides 25 fixtures covering every major quantum SDK, real hardware backends, and testing utilities. All fixtures are auto-discovered with no import needed; just declare them as test parameters.

def test_bell(aer_simulator):    # ← injected automatically
    ...

Fixtures that require an uninstalled SDK are automatically skipped with a helpful message pointing to the install command.


Simulators

aer_simulator

Session-scoped AerSimulator() for shot-based Qiskit simulation.

def test_bell(aer_simulator):
    from qiskit import QuantumCircuit, transpile

    qc = QuantumCircuit(2)
    qc.h(0); qc.cx(0, 1); qc.measure_all()
    counts = aer_simulator.run(transpile(qc, aer_simulator), shots=1024) \
                          .result().get_counts()
    assert "00" in counts

aer_statevector_simulator

Session-scoped AerSimulator(method="statevector") for exact statevectors with no shot noise.

def test_exact(aer_statevector_simulator):
    result = aer_statevector_simulator.run(transpile(qc, aer_statevector_simulator)) \
                                      .result()
    sv = result.get_statevector()

aer_noise_simulator

Function-scoped factory: make_simulator(error_rate), an AerSimulator with configurable depolarizing noise on all gates.

def test_noisy(aer_noise_simulator):
    sim = aer_noise_simulator(error_rate=0.01)   # 1% per-gate depolarizing error
    counts = sim.run(transpile(qc, sim), shots=2000).result().get_counts()
    assert_measurement_distribution(counts, {"00": 0.5, "11": 0.5}, significance=0.001)

cirq_simulator

Session-scoped cirq.Simulator().

def test_cirq(cirq_simulator):
    import cirq
    q = cirq.LineQubit.range(1)
    circuit = cirq.Circuit(cirq.H(q[0]))
    sv = cirq_simulator.simulate(circuit).final_state_vector
    assert sv.shape == (2,)

cirq_sampler

Returns a callable run(circuit, repetitions=1024) dict[str, int] that runs a Cirq circuit with measurements and returns a count dict.

def test_cirq_bell(cirq_sampler):
    import cirq
    q = cirq.LineQubit.range(2)
    circuit = cirq.Circuit(
        cirq.H(q[0]), cirq.CNOT(q[0], q[1]),
        cirq.measure(*q, key="result"),
    )
    counts = cirq_sampler(circuit, repetitions=2000)
    assert_measurement_distribution(counts, {"00": 0.5, "11": 0.5})

braket_simulator

Session-scoped Amazon Braket LocalSimulator().

def test_braket(braket_simulator):
    from braket.circuits import Circuit
    circ = Circuit().h(0).cnot(0, 1).probability()
    result = braket_simulator.run(circ, shots=1000).result()

pennylane_device

Factory: make_device(wires, shots=None), creates a default.qubit device.

def test_pl(pennylane_device):
    import pennylane as qml
    dev = pennylane_device(wires=2)

    @qml.qnode(dev)
    def circuit():
        qml.Hadamard(0); qml.CNOT([0, 1])
        return qml.state()

    state = circuit()
    assert state.shape == (4,)

pytket_circuit_factory

Returns the pytket.Circuit class for building circuits.

def test_pytket(pytket_circuit_factory):
    Circuit = pytket_circuit_factory
    c = Circuit(2)
    c.H(0); c.CX(0, 1)
    assert c.n_qubits == 2

stim_sampler

Returns a callable sample(circuit, shots=1024) dict[str, int] for Stim stabilizer circuits.

def test_stim(stim_sampler):
    import stim
    c = stim.Circuit("H 0\nCNOT 0 1\nM 0 1")
    counts = stim_sampler(c, shots=10000)
    assert_measurement_distribution(counts, {"00": 0.5, "11": 0.5})

graphix_backend

Backend for running graphix MBQC patterns. Returns a _GraphixBackend with .run_pattern(pattern) method.

def test_graphix(graphix_backend):
    from graphix.transpiler import Circuit
    circuit = Circuit(1); circuit.h(0)
    pattern = circuit.transpile().pattern
    sv = graphix_backend.run_pattern(pattern)
    assert sv.shape == (2,)

Qiskit Primitives

qiskit_sampler

Session-scoped StatevectorSampler (Qiskit 1.0+ primitives API).

def test_sampler(qiskit_sampler):
    from qiskit.circuit import QuantumCircuit
    qc = QuantumCircuit(2, 2); qc.h(0); qc.cx(0,1); qc.measure([0,1],[0,1])
    result = qiskit_sampler.run([(qc,)]).result()
    assert_sampler_distribution(result, {"00": 0.5, "11": 0.5})

qiskit_estimator

Session-scoped StatevectorEstimator.

def test_estimator(qiskit_estimator):
    from qiskit.circuit import QuantumCircuit
    from qiskit.quantum_info import SparsePauliOp
    qc = QuantumCircuit(1)   # |0⟩: ⟨Z⟩ = 1.0
    result = qiskit_estimator.run([(qc, SparsePauliOp("Z"))]).result()
    assert_estimator_close(result, expected=1.0, atol=0.01)

Open-System Solvers

qutip_solver

Returns a callable solve(H, psi0, tlist, c_ops=None) np.ndarray that runs the Lindblad master equation via QuTiP.

def test_qubit_decay(qutip_solver):
    import qutip, numpy as np
    H = qutip.sigmaz() / 2
    psi0 = qutip.basis(2, 0)
    gamma = 0.1
    tlist = np.linspace(0, 10, 100)
    rho_final = qutip_solver(H, psi0, tlist, c_ops=[np.sqrt(gamma)*qutip.sigmam()])
    assert_purity_above(rho_final, min_purity=0.0)

tequila_backend

Returns the tequila module for quantum chemistry / VQE tests.

def test_tequila_h(tequila_backend):
    tq = tequila_backend
    U = tq.gates.H(target=0)
    result = tq.simulate(U)
    assert abs(result[0])**2 == pytest.approx(0.5, abs=1e-6)

Real Hardware

All hardware fixtures require --quantum-real to be passed on the CLI and skip automatically otherwise.

ibm_backend

Real IBM Quantum backend. Reads IBM_QUANTUM_TOKEN env var. Uses SamplerV2 primitives.

export IBM_QUANTUM_TOKEN=your_token
pytest --quantum-real tests/hardware/
@pytest.mark.quantum_real
def test_ibm(ibm_backend):
    from qiskit_ibm_runtime import SamplerV2
    from pytest_quantum import assert_measurement_distribution

    sampler = SamplerV2(ibm_backend)
    job = sampler.run([bell_circuit], shots=1024)
    counts = dict(job.result()[0].data.c.get_counts())
    assert_measurement_distribution(counts, {"00": 0.5, "11": 0.5})

Environment variables:

  • IBM_QUANTUM_TOKEN (required)

  • IBM_QUANTUM_BACKEND (optional, defaults to least-busy)

  • IBM_QUANTUM_INSTANCE (optional, defaults to ibm-q/open/main)

ionq_backend

Real IonQ backend. Reads IONQ_API_KEY env var.

export IONQ_API_KEY=your_key
pytest --quantum-real

quantinuum_backend

Real Quantinuum backend via pytket-quantinuum. Reads QUANTINUUM_USERNAME and QUANTINUUM_PASSWORD env vars.

braket_cloud_device

AWS Braket cloud device. Reads BRAKET_DEVICE_ARN and uses AWS credentials from environment.

quantum_hardware_info

Returns a dict of credential availability, useful for dynamic test skipping.

def test_info(quantum_hardware_info):
    print(quantum_hardware_info)
    # {'ibm_available': True, 'ionq_available': False, ...}

Utilities

quantum_benchmark

Quantum-aware benchmark fixture. Uses pytest-benchmark if installed, otherwise a simple timer.

def test_circuit_speed(quantum_benchmark):
    result = quantum_benchmark(run_circuit, my_circuit, shots=1024, n_qubits=5)

benchmark_suite

Collects per-assertion timing data within a test session. (v1.0.0)

def test_assertion_overhead(benchmark_suite):
    import time
    with benchmark_suite.record("assert_unitary"):
        assert_unitary(qc, expected_matrix)
    benchmark_suite.print_summary()

multi_backend_runner

Runs the same circuit on multiple backends in parallel (thread-based) and returns a dict[backend_name, counts]. (v1.0.0)

def test_cross_backend(multi_backend_runner):
    def make_bell():
        qc = QuantumCircuit(2, 2)
        qc.h(0); qc.cx(0, 1); qc.measure([0,1],[0,1])
        return qc

    results = multi_backend_runner.run_all(make_bell, shots=1024)
    for backend, counts in results.items():
        assert_measurement_distribution(counts, {"00": 0.5, "11": 0.5})

shot_budget

Track and enforce total shot usage within a single test.

def test_budget(aer_simulator, shot_budget):
    budget = shot_budget(max_shots=10_000)
    shots = budget.allocate(2000)   # raises if over budget
    # ... run tests ...
    assert budget.remaining == 8000

quantum_shots / quantum_significance

Returns the --quantum-shots / --quantum-significance CLI override values.

def test_with_global_shot_override(quantum_shots):
    shots = quantum_shots or 1024   # use CLI override if provided

@pytest.mark.quantum_backends: parametrised multi-framework tests

Run the same test on multiple backends automatically:

@pytest.mark.quantum_backends("qiskit", "cirq", "pennylane")
def test_h_gate_all_frameworks(quantum_backend, quantum_backend_name):
    # quantum_backend = simulator for current framework
    # quantum_backend_name = "qiskit" | "cirq" | "pennylane"
    print(f"Testing on {quantum_backend_name}")