Skip to content

Commit 071aa5a

Browse files
made tests faster
1 parent 520d4d0 commit 071aa5a

5 files changed

Lines changed: 130 additions & 85 deletions

File tree

.github/workflows/tests.yml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ permissions:
1010
contents: read
1111

1212
jobs:
13-
test:
13+
test-fast:
1414
runs-on: ubuntu-latest
1515
strategy:
1616
fail-fast: false
@@ -43,7 +43,35 @@ jobs:
4343
- name: Run Ruff
4444
run: ruff check .
4545

46-
- name: Run tests
46+
- name: Run fast tests
47+
run: pytest -m "not slow"
48+
49+
test-full:
50+
runs-on: ubuntu-latest
51+
env:
52+
MPLBACKEND: Agg
53+
MPLCONFIGDIR: /tmp/matplotlib
54+
55+
steps:
56+
- name: Check out repository
57+
uses: actions/checkout@v4
58+
59+
- name: Set up Python
60+
uses: actions/setup-python@v5
61+
with:
62+
python-version: "3.12"
63+
cache: pip
64+
cache-dependency-path: |
65+
pyproject.toml
66+
requirements.txt
67+
68+
- name: Upgrade pip
69+
run: python -m pip install --upgrade pip
70+
71+
- name: Install project and dev dependencies
72+
run: pip install -e ".[dev]"
73+
74+
- name: Run full test suite
4775
run: pytest
4876

4977
build:

USAGE.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,34 @@ pip install -e ".[dev]"
2929

3030
---
3131

32+
# Testing and CI
33+
34+
Run the default fast local test pass:
35+
36+
```bash
37+
pytest -m "not slow"
38+
```
39+
40+
Run the slower end-to-end coverage as well:
41+
42+
```bash
43+
pytest
44+
```
45+
46+
Tests marked with `@pytest.mark.slow` are used for heavier CLI and determinism
47+
checks. CI mirrors this split:
48+
49+
• fast tests run across the Python version matrix
50+
• the full suite runs on Python 3.12
51+
52+
Linting remains separate:
53+
54+
```bash
55+
ruff check .
56+
```
57+
58+
---
59+
3260
# Variational quantum classifier (VQC)
3361

3462
Train a minimal variational quantum classifier on a synthetic dataset:

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ include = ["qml*"]
5050
[tool.pytest.ini_options]
5151
testpaths = ["tests"]
5252
addopts = "-q"
53+
markers = [
54+
"slow: slower end-to-end tests kept in the full test pass",
55+
]
5356

5457
[tool.ruff]
5558
line-length = 100
@@ -60,4 +63,4 @@ exclude = [
6063
[tool.black]
6164
line-length = 100
6265
target-version = ["py310"]
63-
extend-exclude = "notebooks/archive"
66+
extend-exclude = "notebooks/archive"

tests/test_cli_smoke.py

Lines changed: 61 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
1+
import io
12
import subprocess
23
import sys
4+
from contextlib import redirect_stderr, redirect_stdout
35

6+
import pytest
47

8+
from qml.__main__ import main
9+
10+
11+
def _run_cli_in_process(monkeypatch: pytest.MonkeyPatch, args: list[str]) -> tuple[int, str, str]:
12+
stdout = io.StringIO()
13+
stderr = io.StringIO()
14+
15+
monkeypatch.setattr(sys, "argv", ["python -m qml", *args])
16+
17+
with redirect_stdout(stdout), redirect_stderr(stderr):
18+
returncode = main()
19+
20+
return returncode, stdout.getvalue(), stderr.getvalue()
21+
22+
23+
@pytest.mark.slow
524
def test_cli_vqc_runs():
625
result = subprocess.run(
726
[
@@ -25,53 +44,43 @@ def test_cli_vqc_runs():
2544
assert "Test accuracy" in result.stdout
2645

2746

28-
def test_cli_kernel_runs():
29-
result = subprocess.run(
47+
def test_cli_kernel_runs(monkeypatch: pytest.MonkeyPatch):
48+
returncode, stdout, _ = _run_cli_in_process(
49+
monkeypatch,
3050
[
31-
sys.executable,
32-
"-m",
33-
"qml",
3451
"kernel",
3552
"--samples",
3653
"20",
3754
],
38-
capture_output=True,
39-
text=True,
4055
)
4156

42-
assert result.returncode == 0
43-
assert "Train accuracy" in result.stdout
44-
assert "Test accuracy" in result.stdout
57+
assert returncode == 0
58+
assert "Train accuracy" in stdout
59+
assert "Test accuracy" in stdout
4560

4661

47-
def test_cli_qcnn_runs():
48-
result = subprocess.run(
62+
def test_cli_qcnn_runs(monkeypatch: pytest.MonkeyPatch):
63+
returncode, stdout, _ = _run_cli_in_process(
64+
monkeypatch,
4965
[
50-
sys.executable,
51-
"-m",
52-
"qml",
5366
"qcnn",
5467
"--samples",
5568
"20",
5669
"--steps",
5770
"2",
5871
],
59-
capture_output=True,
60-
text=True,
6172
)
6273

63-
assert result.returncode == 0
64-
assert "Train accuracy" in result.stdout
65-
assert "Test accuracy" in result.stdout
66-
assert "Final loss" in result.stdout
74+
assert returncode == 0
75+
assert "Train accuracy" in stdout
76+
assert "Test accuracy" in stdout
77+
assert "Final loss" in stdout
6778

6879

69-
def test_cli_regression_runs():
70-
result = subprocess.run(
80+
def test_cli_regression_runs(monkeypatch: pytest.MonkeyPatch):
81+
returncode, stdout, _ = _run_cli_in_process(
82+
monkeypatch,
7183
[
72-
sys.executable,
73-
"-m",
74-
"qml",
7584
"regression",
7685
"--samples",
7786
"20",
@@ -80,62 +89,50 @@ def test_cli_regression_runs():
8089
"--layers",
8190
"1",
8291
],
83-
capture_output=True,
84-
text=True,
8592
)
8693

87-
assert result.returncode == 0
88-
assert "Train MSE" in result.stdout
89-
assert "Test MSE" in result.stdout
90-
assert "Final loss" in result.stdout
94+
assert returncode == 0
95+
assert "Train MSE" in stdout
96+
assert "Test MSE" in stdout
97+
assert "Final loss" in stdout
9198

9299

93-
def test_cli_logistic_runs():
94-
result = subprocess.run(
100+
def test_cli_logistic_runs(monkeypatch: pytest.MonkeyPatch):
101+
returncode, stdout, _ = _run_cli_in_process(
102+
monkeypatch,
95103
[
96-
sys.executable,
97-
"-m",
98-
"qml",
99104
"logistic",
100105
"--samples",
101106
"20",
102107
],
103-
capture_output=True,
104-
text=True,
105108
)
106109

107-
assert result.returncode == 0
108-
assert "Train accuracy" in result.stdout
109-
assert "Test accuracy" in result.stdout
110+
assert returncode == 0
111+
assert "Train accuracy" in stdout
112+
assert "Test accuracy" in stdout
110113

111114

112-
def test_cli_ridge_runs():
113-
result = subprocess.run(
115+
def test_cli_ridge_runs(monkeypatch: pytest.MonkeyPatch):
116+
returncode, stdout, _ = _run_cli_in_process(
117+
monkeypatch,
114118
[
115-
sys.executable,
116-
"-m",
117-
"qml",
118119
"ridge",
119120
"--samples",
120121
"20",
121122
],
122-
capture_output=True,
123-
text=True,
124123
)
125124

126-
assert result.returncode == 0
127-
assert "Train MSE" in result.stdout
128-
assert "Test MSE" in result.stdout
129-
assert "Train MAE" in result.stdout
130-
assert "Test MAE" in result.stdout
125+
assert returncode == 0
126+
assert "Train MSE" in stdout
127+
assert "Test MSE" in stdout
128+
assert "Train MAE" in stdout
129+
assert "Test MAE" in stdout
131130

132131

133-
def test_cli_trainable_kernel_runs():
134-
result = subprocess.run(
132+
def test_cli_trainable_kernel_runs(monkeypatch: pytest.MonkeyPatch):
133+
returncode, stdout, _ = _run_cli_in_process(
134+
monkeypatch,
135135
[
136-
sys.executable,
137-
"-m",
138-
"qml",
139136
"trainable-kernel",
140137
"--samples",
141138
"20",
@@ -146,12 +143,10 @@ def test_cli_trainable_kernel_runs():
146143
"--embedding-layers",
147144
"1",
148145
],
149-
capture_output=True,
150-
text=True,
151146
)
152147

153-
assert result.returncode == 0
154-
assert "Train accuracy" in result.stdout
155-
assert "Test accuracy" in result.stdout
156-
assert "Final alignment" in result.stdout
157-
assert "Final loss" in result.stdout
148+
assert returncode == 0
149+
assert "Train accuracy" in stdout
150+
assert "Test accuracy" in stdout
151+
assert "Final alignment" in stdout
152+
assert "Final loss" in stdout

tests/test_noise_smoke.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import pytest
2+
13
from qml.benchmarks import compare_classification_models, compare_regression_models
24

35

46
def test_classification_benchmark_accepts_noise_aware_model_kwargs():
57
result = compare_classification_models(
6-
models=["vqc", "kernel", "trainable_quantum_kernel"],
8+
models=["vqc", "kernel"],
79
seeds=[7],
810
n_samples=24,
911
noise=0.1,
@@ -16,12 +18,6 @@ def test_classification_benchmark_accepts_noise_aware_model_kwargs():
1618
"kernel": {
1719
"shots": 4,
1820
},
19-
"trainable_quantum_kernel": {
20-
"embedding": "angle",
21-
"steps": 0,
22-
"shots_train": 4,
23-
"shots_kernel": 4,
24-
},
2521
},
2622
save=False,
2723
)
@@ -30,14 +26,12 @@ def test_classification_benchmark_accepts_noise_aware_model_kwargs():
3026
assert result["models"] == [
3127
"vqc",
3228
"quantum_kernel",
33-
"trainable_quantum_kernel",
3429
]
3530

3631
assert "vqc" in result["summary"]
3732
assert "quantum_kernel" in result["summary"]
38-
assert "trainable_quantum_kernel" in result["summary"]
3933

40-
assert len(result["runs"]) == 3
34+
assert len(result["runs"]) == 2
4135

4236
for run in result["runs"]:
4337
assert "model" in run
@@ -46,18 +40,14 @@ def test_classification_benchmark_accepts_noise_aware_model_kwargs():
4640
assert "test_accuracy" in run
4741

4842

43+
@pytest.mark.slow
4944
def test_classification_benchmark_finite_shot_runs_are_deterministic_for_fixed_seed():
5045
kwargs = {
51-
"models": ["vqc", "kernel"],
46+
"models": ["kernel"],
5247
"seeds": [11],
5348
"n_samples": 24,
5449
"noise": 0.1,
5550
"model_kwargs": {
56-
"vqc": {
57-
"n_layers": 1,
58-
"steps": 2,
59-
"shots": 4,
60-
},
6151
"kernel": {
6252
"shots": 4,
6353
},
@@ -102,6 +92,7 @@ def test_regression_benchmark_accepts_noise_aware_model_kwargs():
10292
assert "test_mae" in run
10393

10494

95+
@pytest.mark.slow
10596
def test_regression_benchmark_finite_shot_runs_are_deterministic_for_fixed_seed():
10697
kwargs = {
10798
"models": ["vqr"],

0 commit comments

Comments
 (0)