Pyjo.Test.pytest_plugin - Pyjoyment in pytest

$ pytest
$ pytest -v t/basic.py

# pyproject.toml
[tool.pytest.ini_options]
testpaths = ["t", "tests"]
pythonpath = ["."]

# tests/conftest.py
import pytest


@pytest.fixture
def app():
    return 'MyApp'


# tests/test_basic.py
def test_index(t):
    t.get_ok('/').status_is(200).content_like(r'Pyjoyment')

Pyjo.Test.pytest_plugin is a plugin of pytest, which pytest loads where Pyjoyment is installed. It runs the test scripts of Pyjo.Test as Pyjo.Prove does, each as a test of pytest, and lets the tests of pytest use Pyjo.Test and Pyjo.Test.Pyjo. Pyjo.Prove stays the runner of the test scripts, and pytest runs the same scripts for whoever runs pytest, as a test explorer of an IDE or a coding agent. Pyjoyment does not depend on pytest, and nothing of it but this plugin imports pytest.

It has no counterpart in Mojolicious.

Test scripts

A file with the extension .py in the directories of pyjo_prove_paths, t by default, is a test script, whatever its name, but conftest.py, and pytest does not import it. The script runs in a process of its own, in the root directory of pytest, with Pyjo.Prove.run_script(), and is a test of pytest of its own, t/basic.py, which passes, fails or is skipped as Pyjo.Prove reports the script. The report of a failure shows the failed tests, the standard error of the script with their diagnostic messages, and what is wrong with the plan or the exit status; the whole TAP output of the script is its captured standard output. Bail out! stops the run.

pytest runs its tests one after another, and so the test scripts, where Pyjo.Prove runs several at the same time with -j; -n of pytest-xdist does so, as each test script is a test of its own.

The scripts get the environment that pytest started with, as python -m Pyjo.Prove -l gives it to them: the root directory in PYTHONPATH, PYJO_HARNESS_ACTIVE, and PYJO_HARNESS_IS_VERBOSE with -v.

pytest without arguments runs the directories of testpaths, so a project whose tests are test scripts names their directory there, in pyproject.toml, as the projects of generate app and generate plugin do, with pytest in the dependency group dev, which uv run pytest installs:

[dependency-groups]
dev = ["pytest>=9", "pytest-xdist>=3"]

[tool.pytest.ini_options]
testpaths = ["t"]
pythonpath = ["."]

Tests of pytest

The plugin calls Pyjo.Test.raise_failures(), so that a failed test of Pyjo.Test or of Pyjo.Test.Pyjo raises AssertionError with its name and its diagnostic message, plan(skip_all=...) skips the test, and Bail out! stops the run.

A test stops at its first failed test, after which success and otherwise() have nothing to do. The user agent of Pyjo.Test.Pyjo blocks, so a test is a function, not a coroutine. The tests run in one process, where their applications share the singleton of Pyjo.IOLoop and the environment, which a test script has of its own. The tests go to a directory of their own, as tests, as Pyjo.Prove runs every script in t, and pythonpath of pytest puts the root directory in sys.path, as -l of Pyjo.Prove does for the test scripts, so that a test finds the application by the name of its class.

Ini options

pyjo_prove_paths

The directories of the test scripts, relative to the configuration file, t of the root directory by default. Without a directory, pytest runs no test scripts.

[tool.pytest.ini_options]
pyjo_prove_paths = ["t", "xt"]
pyjo_prove_timeout

The most seconds a test script may run, no limit by default. A test script that runs longer is killed, with the processes it started, and fails.

[tool.pytest.ini_options]
pyjo_prove_timeout = "60"

Fixtures

t

A Pyjo.Test.Pyjo object of the application of the fixture app, which the tests define, and which can be anything that Pyjo.Test.Pyjo.Pyjo_Test_Pyjo.__init__() takes. The end of the test closes it.

@pytest.fixture
def app():
    return Pyjo.File.curfile().dirname().sibling('myapp.py')


def test_index(t):
    t.get_ok('/').status_is(200)

See also

Pyjoyment, https://docs.pytest.org.

class Pyjo.Test.pytest_plugin.ScriptItem(*k, **kw)[source]

The test of pytest that runs a test script.

config

The pytest config object.

name

A unique name within the scope of the parent node.

parent

The parent collector node.

path

Filesystem path where this node was collected from.

reportinfo() → tuple[Path, None, str][source]
path, line, name = item.reportinfo()

The path of the test script, without a line, and its name in the headline of the report of a failure, as t/basic.py (TAP).

runtest() → None[source]
item.runtest()

Run the test script with Pyjo.Prove.run_script(), and fail or skip as its result says.

session

The pytest session this node is part of.