Installation and First Test
Pytest installs as a single package, and the first test needs nothing but the package and a test_*.py file. The pip install pytest pulls the framework plus its default plugins, the pytest command is the entry point, and the first run collects the test_*.py files from the current directory and its subdirectories. This chapter covers the install (the pip, the --version check, the plugin list), the first test (the test_texttools.py against the running example), the -v verbose output, the exit code, and the minimal command flags the daily run uses (the -v, the -q, the -x, the -k).
The Install
# the install: the single package (the venv first)
python -m venv .venv
source .venv/bin/activate
pip install pytest
# the verify: the version + the python + the rootdir
pytest --version
# pytest 8.x.x
# plugins: cov-5.x, mock-3.x, asyncio-0.x
# the plugins are the installed pytest-* packages (the
# pytest-cov, the pytest-mock, the pytest-asyncio) - the
# --version lists them, the -VV lists the hooks each
# plugin registers (the plugin's the deep inspect)
pip install -e ".[dev]" # the project's dev extra (the
# pytest + the plugins, the venv's)
The install is the one pip package: the pytest command and the assertion rewriter, with the plugins that are already installed in the environment listed by the --version (the pytest-cov, the pytest-mock, the pytest-asyncio - each a separate pytest-* package the project's dev extra installs). The python -m pytest form is the equivalent when the PATH does not have the pytest script (the venv's bin not activated), and the --version is the three-part check (the pytest version, the Python version, the rootdir) that confirms the environment before the first run. The project's [dev] extra (the pip install -e ".[dev]") is the repeatable form: the editable install of the package under test plus the test dependencies in one command, the requirements the team shares.
The First Test
# the texttools/word.py (the module under test)
def word_count(text):
return len(text.split())
# the tests/test_word.py (the FIRST test)
from texttools import word_count
def test_empty():
assert word_count("") == 0
def test_single():
assert word_count("hello") == 1
def test_multiple():
assert word_count("the quick brown fox") == 4
# the run: the pytest from the project root
pytest
# the collection (the 3 items), the run (the 3 passed),
# the report (the 3 passed in 0.01s)
# the verbose: the per-item line (the name + the PASSED)
pytest -v
# tests/test_word.py::test_empty PASSED
# tests/test_word.py::test_single PASSED
# tests/test_word.py::test_multiple PASSED
# the exit code (the shell's $?, the CI's the signal):
pytest -q; echo $?
# 0 = the all passed (the green)
# 1 = the at least one failed (the red)
The first test is three plain functions in the tests/test_word.py, each a bare assert against the texttools.word_count - the discovery finds them by the test_ prefix, and the pytest command runs them from the project root. The output is the three phases: the collection count, the run, and the report (the 3 passed in 0.01s). The -v adds the per-item line (the test_word.py::test_empty PASSED - the file, the function, the result), which is the form the CI log reads, and the exit code (the $? after the run) is the 0 the all-passed and the 1 the failure - the two values the pipeline branches on. The -q is the quiet (the one-line summary), and the next chapter's -x and the -k are the stop-on-first-failure and the name-filter - the three flags the daily pytest -x -q run uses while developing, and the full pytest -v the commit gate.
The Daily Flags
# the -x: the stop on the FIRST failure (the dev's
# the fast loop - the fix, the rerun, the no scroll
# through the 200 failures)
pytest -x -q
# the the first red stops the session (the the rest
# not collected-run, the the fix is the the focused)
# the -k: the name FILTER (the substring, the "and" /
# the "or" / the "not" expressions)
pytest -k "palindrome"
# the run ONLY the test with "palindrome" in the name
pytest -k "cipher and not reverse"
# the the subset (the the boolean expression on the name)
# the path: the single FILE or the single TEST
pytest tests/test_word.py
pytest tests/test_word.py::test_multiple
# the the targeted run (the the fix the the one test,
# the the CI the the full suite)
# the -s: the show the print (the capture OFF, the
# the stdout live) - the the debug the the print
pytest -s -k word_count
The daily flags are the four that shorten the loop. The -x stops the session at the first failure (the dev's fix-rerun cycle - the no scroll through the remaining failures), the -k filters by the test name (the substring, the and/or/not expression - the run the one feature being worked on), the path argument targets the single file or the single test (the tests/test_word.py::test_multiple - the fix verified against the one red), and the -s disables the capture so the print shows live (the debug the state the assert does not reveal). The combination the dev uses is the pytest -x -q -k "the-feature" while iterating, and the full pytest -v before the commit - the two modes (the fast targeted, the complete verbose) are the workflow the flags make possible, and the conftest plus the pyproject (the next chapters) move the repeated flags into the configuration so the bare pytest already runs the right way.
The Working Rules
- The venv first, the
pip install pytestsecond. Thepython -m venvplus the activate is the isolation, the--versionthe three-part check (the version, the Python, the rootdir), and the project's[dev]extra the repeatable install of the package plus the test dependencies. - The test is the
test_*.pyfile, thetest_*function. The discovery finds them by the name, the bareassertis the check, and thepytestfrom the project root runs the whole suite - the no registration, the no__main__. - The
-vis the per-item line, the exit code is the CI's signal. Thetest_file.py::test_name PASSEDthe log reads, the0the green and the1the red the pipeline branches on (the2the collection error, the5the no-tests). - The
-x/-k/path/-sare the dev's loop. The stop-on-first-failure, the name filter, the single-file run, and theprintlive - thepytest -x -q -k "feature"while iterating, thepytest -vthe commit gate.
Summary
Pytest installs as the single pip package (the venv first, the pip install pytest second, the --version the version/Python/rootdir check, the project's [dev] extra the repeatable install of the package plus the test plugins). The first test is the tests/test_word.py with the plain test_* functions and the bare assert against the texttools module, and the pytest command runs the three phases (the collection, the run, the report) from the project root. The -v is the per-item line the CI log reads, the exit code is the 0/1/2/5 the pipeline branches on, and the daily flags - the -x the stop-on-first-failure, the -k the name filter, the path the single-file run, and the -s the capture off - make the pytest -x -q -k "feature" the dev's loop and the pytest -v the commit gate. The next chapter moves from the command flags to the discovery rules: the naming conventions, the rootdir, and the conftest.py the configuration's anchor.