Skip to content

API Reference

Test Runner

pytest.main(args=None)

Run tests with the given arguments. Returns exit code (0 = all passed).

import oxytest as pytest
exit_code = pytest.main(["-v", "tests/"])

pytest.discover_tests(root_dir, pattern=None)

Discover tests in a directory. Returns list of TestItem objects.

from oxytest import discover_tests
tests = discover_tests("tests/")

pytest.run_tests(tests, num_workers=None, nocapture=False)

Run tests in parallel using Rayon thread pool.

pytest.run_tests_sequential(tests, nocapture=False)

Run tests sequentially in the current thread.

Assertions

pytest.approx(expected, rel=None, abs=None, nan_ok=False)

Assert approximate equality for floating-point numbers.

assert 0.1 + 0.2 == pytest.approx(0.3)

pytest.raises(expected_exception, match=None)

Assert that a block raises an exception.

with pytest.raises(ValueError, match="invalid"):
    int("invalid")

Assert Rewriting

Oxytest automatically rewrites assert statements to produce detailed comparison diffs:

# Instead of: AssertionError
# You get:   AssertionError: assert 1 == 2
#                               1 == 2
assert x == y

# With --showlocals:
#   AssertionError: assert 1 == 2
#                   1 == 2
#
#   Locals:
#     x = 1
#     y = 2

Fixtures

pytest.fixture(scope="function", params=None, autouse=False, name=None)

Decorator to define a fixture.

@pytest.fixture
def database():
    db = create_database()
    yield db
    db.close()

@pytest.fixture(scope="module", autouse=True)
def setup_once():
    print("runs once per module before any test")

Yield Fixtures

Yield fixtures automatically run teardown after the test:

@pytest.fixture
def resource():
    print("setup")
    yield value
    print("teardown")  # runs after test

Built-in Fixtures

Fixture Description
tmp_path Temporary directory (pathlib.Path), cleaned after test
tmpdir Temporary directory (str), legacy
capsys Capture stdout/stderr during test
capfd Capture file descriptors during test
monkeypatch Monkey-patch attributes, environment, and dicts
def test_with_tmp_path(tmp_path):
    d = tmp_path / "subdir"
    d.mkdir()
    assert d.exists()

def test_capture(capsys):
    print("hello")
    out, err = capsys.readouterr()
    assert "hello" in out

Markers

pytest.mark.parametrize(argnames, argvalues)

Run a test multiple times with different arguments.

@pytest.mark.parametrize("x,expected", [(1, 2), (3, 6)])
def test_double(x, expected):
    assert x * 2 == expected

pytest.mark.skip(reason=None)

Skip a test.

@pytest.mark.skip(reason="not implemented")
def test_todo():
    pass

pytest.mark.skipif(condition, reason=None)

Skip a test conditionally.

import sys
@pytest.mark.skipif(sys.version_info < (3, 10), reason="needs 3.10+")
def test_new_feature():
    pass

pytest.mark.xfail(reason=None, condition=None, raises=None, strict=None)

Mark a test as expected to fail.

@pytest.mark.xfail(reason="known issue")
def test_flaky():
    assert False

pytest.mark.usefixtures(*names)

Apply fixtures to a test or class without injecting them as parameters.

@pytest.mark.usefixtures("database")
class TestSuite:
    def test_query(self):
        ...  # database fixture is active

@pytest.mark.usefixtures("setup")
def test_with_setup():
    ...

Utilities

pytest.skip(reason)

Skip the current test imperatively.

pytest.fail(reason)

Fail the current test imperatively.

pytest.importorskip(modname, minversion=None, reason=None)

Import a module or skip if not available.

pytest.set_trace()

Drop into a debugger (uses pdb).

pytest.exit(exit_code=0)

Exit the test session.

pytest.param(values, id=None, marks=None)

Create a parametrize argument with custom id or marks.

@pytest.mark.parametrize("x", [
    pytest.param(1, id="one"),
    pytest.param(2, marks=pytest.mark.skip),
])
def test_values(x):
    ...

Plugin System

hookimpl(tryfirst=False, trylast=False, hookwrapper=False)

Decorator for plugin hook implementations.

from oxytest import hookimpl

@hookimpl
def pytest_addoption(parser):
    parser.addoption("--my-flag", action="store_true")

@hookimpl(tryfirst=True)
def pytest_configure(config):
    value = config.getoption("--my-flag")

hookspec(tryfirst=False, trylast=False)

Decorator for defining hook specifications.

Config

Holds parsed CLI options and plugin state.

from oxytest import Config
config = Config(opts)
value = config.getoption("--my-flag")

Parser

Minimal argparse-like interface for pytest_addoption hooks.

parser.addoption("--my-flag", action="store_true", help="...")

PluginManager

Manages plugin registration and hook calling.

from oxytest import get_plugin_manager
pm = get_plugin_manager()
pm.load_entry_point_plugins()

get_plugin_manager()

Get the singleton plugin manager instance.

Migration Tool

# Preview migration from pytest → oxytest
oxytest migrate src/ --dry-run

# Perform migration
oxytest migrate src/

# Reverse: oxytest → pytest
oxytest migrate src/ --reverse

# Check-only (exit code 1 if any pytest imports found)
oxytest migrate src/ --check

CLI Flags

Flag Description
-v, --verbose Increase verbosity
-q, --quiet Quiet output
-x, --exitfirst Stop on first failure
-k EXPR Filter tests by keyword
--tb=style Traceback style (short, long, native, no)
-n WORKERS Number of parallel workers (auto = CPU count)
--junitxml=PATH Generate JUnit XML report
-s Don't capture stdout/stderr
--maxfail=N Stop after N failures
-p PLUGIN Load plugin (repeatable)
--ignore=PATH Ignore test path (repeatable)
--collect-only, --co Only collect tests
--durations=N Show N slowest tests
-r[chars] Extra summary (-rA, -rf, -rs)
--showlocals Show local variables in tracebacks
--strict-markers Unknown markers cause errors
--rootdir=PATH Set root directory for discovery
--fixtures List available fixtures
--markers List registered markers
--setup-show Print fixture setup/teardown
--cache-clear Clear cache before run
--lf, --last-failed Run only previously failed tests
--ff, --failed-first Run failed tests first
--pdb Drop into debugger on failure
--trace Drop into debugger before each test
--cov[=SOURCE] Measure code coverage
--cov-report=TYPE Coverage report type (term, html, xml)
--cov-config=FILE Config file for coverage
--cov-branch Enable branch coverage
--cov-fail-under=N Fail if coverage below N%
--cov-append Append to existing coverage data
--version Show version
-h, --help Show help

Exit Codes

Code Meaning
0 All tests passed
1 Some tests failed
2 Test execution error
4 No tests collected