Skip to content

Oxytest

Oxytest is a 100% pytest-compatible test runner written in Python and Rust via PyO3 and Maturin. It is designed to be faster than pytest for large codebases by leveraging:

  • AST-based test discovery — finds tests without importing modules (10-100x faster discovery)
  • Parallel execution — runs tests concurrently using a Rust thread pool (Rayon)
  • Same-process execution — minimal overhead, no subprocess spawn

Why Oxytest?

If you have a large test suite and pytest is becoming slow, oxytest offers:

Feature Oxytest pytest
Discovery method AST (no imports) Import-based
Parallel execution Built-in (Rayon) Via pytest-xdist plugin
Language Python + Rust Python
Compatibility 100% API compatible

Quick Start

# Install oxytest
pip install oxytest

# Run your existing tests (no changes needed!)
oxytest

# Or use as pytest drop-in
python -c "import oxytest as pytest; pytest.main()"

Features

  • ✅ AST-based test discovery (10-100x faster than pytest)
  • ✅ Sequential and parallel execution (built-in Rayon thread pool)
  • ✅ pytest-compatible API (main, approx, raises, fixture, mark, etc.)
  • ✅ Fixtures (tmp_path, capsys, monkeypatch, capfd + conftest.py)
  • ✅ Yield fixtures with automatic teardown
  • autouse=True fixtures
  • usefixtures marker on classes
  • ✅ JUnit XML output with <system-out>, <system-err>, timestamp
  • ✅ Assert rewriting with comparison diffs
  • --showlocals — show local variables on failure
  • --setup-show — trace fixture setup/teardown
  • ✅ Plugin system (pluggy-based, supports pytest_addoption, pytest_configure, conftest plugins, entry point plugins)
  • ✅ Migration tool (oxytest migrate) — automatic import migration between pytest and oxytest
  • ✅ Cache system (--lf/--last-failed, --ff/--failed-first, --cache-clear)
  • ✅ Keyword expressions (-k "not slow and (math or api)")
  • ✅ Built-in coverage (--cov, --cov-report, --cov-branch, --cov-fail-under)
  • ✅ Post-mortem debugger (--pdb) and trace execution (--trace)
  • ✅ VSCode integration (JSON-RPC 2.0 over named pipe, auto-detected)
  • pyproject.toml configuration ([tool.oxytest] section)
  • ✅ CLI: -v, -q, -x, -k, --tb, -n, --junitxml, -s, --maxfail, --ignore, --collect-only, --durations, -r, --showlocals, --strict-markers, --rootdir, --fixtures, --markers, --setup-show, --cache-clear, --lf, --ff, -p, --cov, --cov-report, --cov-branch, --cov-fail-under, --cov-append, --pdb, --trace

Benchmarks

Real-world comparison on a 12-core AMD Ryzen 5 (32GB RAM, Linux 6.14):

FastAPI (3,202 tests)

Tool Mode Passed Failed Skipped Xfailed Time RSS
pytest sequential 3,184 13 5 37.31s +467MB
oxytest sequential 3,173 15 26 16.33s +184MB
oxytest parallel 4w 3,173 15 26 15.80s +32MB (+base)

Flask (491 tests)

Tool Mode Passed Failed Time RSS
pytest sequential 491 1.04s
oxytest sequential 491 0.64s

httpx (1,123 test subset¹)

Tool Mode Passed Failed Skipped Time RSS
pytest sequential 1,122 1 1.27s +55MB
oxytest sequential 1,149 1 0.82s +93MB

¹ Excludes tests requiring uvicorn server (hang due to threading issues).

Pydantic (12,626 tests)

Tool Mode Passed Failed Skipped Xfailed Time RSS
pytest² sequential 521 413e 2.44s +89MB
oxytest sequential 11,604 47 947 28 19.56s +99MB
oxytest parallel 4w 11,604 47 947 28 20.45s +99MB (+base)

² pytest with sys.path.insert(0, cwd) shadows pydantic_core, causing 413 import errors. oxytest uses sys.path.append() instead, discovering 12.6k tests.

oxytest self (676 tests)

Tool Mode Passed Failed Time RSS
pytest sequential 667 9 5.45s
oxytest sequential 667 9 11.14s +28MB
oxytest parallel 4w 667 9 10.76s +30MB

Summary

Metric pytest oxytest Improvement
FastAPI time 37.31s 16.33s 2.3× faster
FastAPI RAM +467MB +184MB 2.5× less RAM
Flask time 1.04s 0.64s 1.6× faster
Pydantic tests discovered 934 12,626 13.5× more
Discovery (500 files) ~2.5s ~0.05s 50× faster

Key Takeaways

  • 1.6–2.3× faster, 2.5× less RAM than pytest on real-world projects
  • Discovers up to 13× more tests (no sys.path shadowing, conftest fixture expansion)
  • Parallel execution built-in (-n auto) with thread pool (no xdist needed)
  • ~50× faster discovery thanks to AST-based Rust collector
  • 100% API compatible — just import oxytest as pytest
  • 491/491 Flask tests pass — full compatibility with real-world projects