pytest install and first test: plain asserts and fixtures for Python
The pytest framework makes it easy to write small tests, yet scales to support complex functional testing
At a glance
- What is it?
- pytest is a mature Python testing framework under the MIT license. It replaces unittest's self.assert* methods with assertion introspection, fixtures and parametrization, at the cost of a framework you have to learn on its own terms.
- Who is it for?
- Adopt pytest if your project runs Python 3.10+ and you want assertion introspection, fixtures and parametrization without writing self.assert* calls. Do not adopt it if you need one runner across non-Python languages, or if you cannot add a dependency to your test environment, since unittest ships with the interpreter.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What pytest replaces, and who it is for
The problem pytest addresses is the cost of writing and reading assertions in Python's standard unittest module. unittest requires named assertion methods (self.assertEqual, self.assertTrue and the rest), and when one fails the traceback points at the method rather than showing the values that produced the failure. pytest's README states that its detailed assertion introspection lets you "simply use plain assert statements", and the example it gives is a function inc(x) returning x + 1 with a test asserting inc(3) == 5. The failure output the README shows includes the line assert 4 == 5 plus the derived line where 4 = inc(3), so the values are visible without extra print calls.
The audience is Python application and library developers. The repository's pyproject.toml declares requires-python >=3.10 and classifiers for CPython 3.10 through 3.15, and the README adds Python 3.10+ or PyPy3. The project is not new: the LICENSE file carries copyright Holger Krekel and others, 2004, and the classifier is Development Status :: 6 - Mature. If you maintain a suite that already uses unittest, the README states pytest can run unittest test suites out of the box, which means migration can be incremental rather than a rewrite. The README's own framing is that the framework makes it easy to write small tests yet scales to support complex functional testing, and that second half is what the rest of this article examines.
Assertion introspection, fixtures and auto-discovery
Three mechanisms do most of the work. The first is assertion rewriting: when a test module is imported, pytest rewrites the assert statements so that a failure reports the sub-expressions and their values. That is why the README's example can print both assert 4 == 5 and where 4 = inc(3) from a single line of test code. You do not call a helper to get this; the rewriting happens at import time.
The second is modular fixtures, which the README describes as a way to manage "small or parametrized long-lived test resources". A fixture is a function that a test requests by naming it as a parameter. pytest resolves the dependency graph, constructs the resource, and tears it down afterwards. Fixtures compose, so a session-scoped database connection can be shared while a function-scoped transaction is rolled back per test. This is where the framework stops being a thin wrapper over assert and becomes an architecture you have to design deliberately.
The third is auto-discovery of test modules and functions. You do not register tests in a manifest; pytest walks the tree, imports files matching its test naming conventions, and collects test functions. The README's transcript shows the result: collected 1 items, then the failure, then 1 failed in 0.04 seconds. The pyproject.toml lists pluggy>=1.5,<2 as a runtime dependency, which is the hook layer the README's "rich plugin architecture" is built on; the README states there are over 1300+ external plugins. Configuration lives in files such as pyproject.toml or tox.ini, both of which appear in the repository's top-level entries. Parametrization is the piece that connects the second and third mechanisms: one test function can be run against many input sets, and each set is collected and reported separately.
Installing pytest and running a first failing test
pytest is distributed on PyPI under the package name pytest, which the RELATED SEARCHES list reflects with the phrases "Pytest PyPI" and "Pytest pip". The README points to https://docs.pytest.org/en/stable/ for installation instructions. A pip install into the active environment is the shortest path:
pip install pytestAfter that, the pytest console script is on your PATH. Create the file the README uses as its example:
# content of test_sample.py
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 5Run it with no arguments from the directory containing the file:
pytestThe README shows the expected output: a test session header, collected 1 items, the failing test named test_answer, the assertion line assert 4 == 5 with the derived value, the file and line number, and a summary reading 1 failed. The failure is intentional in the README's example; changing the assertion to assert inc(3) == 4 turns it green. If you prefer conda, the README's badge links to the conda-forge package, so pytest is also installable from that channel.
Where pytest is the wrong tool
pytest tests Python. If your system is polyglot and you want one runner and one report format across Go, Java and TypeScript, pytest will not give you that. It is a Python framework with a Python plugin API, and the 1300+ plugins the README mentions are overwhelmingly Python packages. Reaching for it as a general-purpose test orchestrator means shelling out to other runners and parsing their output yourself.
The dependency footprint is a second boundary. Installing pytest pulls in iniconfig>=2, packaging>=24, pluggy>=1.5,<2 and pygments>=2.15, plus colorama on Windows and tomli and exceptiongroup on Python versions below 3.11. unittest needs none of that because it ships with CPython. In a locked-down environment where every added package needs review, that difference matters.
Version pinning is the third. requires-python is >=3.10, so a codebase still on 3.9 cannot install current pytest without also upgrading the interpreter. And there is a subtler cost: fixtures and parametrization are conventions, not enforced structure. A suite can end up with fixture chains that are hard to follow, and nothing in the framework prevents that. The README does not describe a migration path back to unittest, so treat adoption as a one-way door for the test code you convert. Finally, the README documents no built-in coverage collection; teams that want it reach for the pytest-cov plugin, which is a separate package with its own release cadence.
pytest versus unittest: the actual difference
The two frameworks differ in where structure comes from. unittest organizes tests as methods on a class inheriting from TestCase, with setUp and tearDown methods and named assertion helpers. pytest organizes tests as plain functions, resolves shared resources through fixtures named in the function signature, and lets you write bare assert statements. That is the core of the "pytest vs unittest" comparison people search for.
The practical consequence is in failure output and in reuse. A unittest failure points at the assertion method; the pytest output in the README points at the expression and the values behind it, so you spend less time adding print statements to find out what actually differed. Reuse in unittest comes from inheritance and mixins; reuse in pytest comes from fixtures, which the README describes as modular and parametrizable, and from parametrized test functions that generate one collected item per input set.
The two are not mutually exclusive. The README states pytest can run unittest (or trial) test suites out of the box, so a team can keep existing TestCase classes and write new tests in pytest style in the same run. If your organization already standardizes on unittest and the suite is large, the incremental path is real and low risk. If you are starting a new Python project, the fixture model is the reason to pick pytest, and it is also the thing you will spend the most time learning. Neither framework is a mistake; the choice is about whether you want configuration through class hierarchies or through function signatures.
Licence, maintenance and upgrade cost
pytest is distributed under the MIT license, and the pyproject.toml declares license = "MIT" with license-files = [ "LICENSE" ]. MIT is permissive: it allows use, modification and redistribution, including in proprietary products, provided the copyright notice and permission notice are retained. That is a description of the licence text, not legal advice; if you vendor pytest or ship it inside a product, have your own counsel read the LICENSE file.
The repository is not archived, and the last push was on 2026-09-21. Releases are frequent enough to plan around: 9.1.1 on 2026-06-19, 9.1.0 on 2026-06-13 and 9.0.3 on 2026-04-07. The changelog lives in the CHANGELOG.rst file and the changelog/ directory, and the README points to the changelog page for fixes and enhancements in each version. Upgrades are not free: a major bump can change behaviour that your plugins or fixtures depend on, and the plugin ecosystem is the part most likely to lag behind a new release. Pin pytest in your test requirements and read the changelog entry for the target version before bumping.
Commercial support exists through the Tidelift subscription the README describes; the maintainers are also funded through the Open Collective linked in the README. Security issues are not handled in the public issue tracker: the README asks that vulnerabilities be reported through a new security advisory on GitHub instead. For a test-only dependency the licence risk is low, but the upgrade cadence is not zero, because a red suite after a bump is usually a plugin problem rather than a framework problem.
Verifying pytest before you commit to it
The cheapest check is collection. Run pytest against your existing suite and read the count and the file list. If pytest imports a module that has side effects at import time, you will see it there rather than in the middle of a test run. This also tells you how much of your suite pytest will actually pick up under its naming conventions, which is the number that decides whether adoption is a small change or a project of its own.
The second check is the interpreter. requires-python is >=3.10, so confirm your target version before installing; the classifiers cover 3.10 through 3.15. The third is your plugin list. Because pluggy is a runtime dependency and plugins hook into collection and execution, a plugin that has not been updated for the pytest version you install is the most common source of surprises. Install into a virtual environment first, run the suite, and only then change the pin in your project's test requirements. If you need coverage numbers, plan for the pytest-cov plugin as a separate dependency with its own compatibility window.
Editorial conclusion
Adopt pytest if your project runs Python 3.10+ and you want assertion introspection, fixtures and parametrization without writing self.assert* calls. Do not adopt it if you need one runner across non-Python languages, or if you cannot add a dependency to your test environment, since unittest ships with the interpreter. Before committing, verify that the version you install supports your interpreter (requires-python is >=3.10) and run pytest on an existing suite to see how many tests it collects before any of them execute.
Frequently asked questions
What is pytest in Python?
pytest is a testing framework for Python applications and libraries. The README describes it as making it easy to write small tests while scaling to complex functional testing, and it runs plain assert statements with detailed introspection on failure.
Is pytest difficult to learn?
The README's first example is a two-function file run with a single pytest command, so the entry point is small. The parts that take longer are fixtures, which the README describes as modular and parametrizable, and the plugin architecture built on pluggy.
How do I run a pytest test in Python?
Run the pytest command from the directory containing your test file. The README's transcript shows the session header, the collected item count, the failing test and a summary line such as 1 failed in 0.04 seconds.
How do I install pytest?
Install the pytest package from PyPI with pip, or from the conda-forge channel whose badge the README links. The README points to https://docs.pytest.org/en/stable/ for full installation instructions.
How do I use pytest fixtures?
A fixture is a function a test requests by naming it as a parameter; pytest resolves the dependency, builds the resource and tears it down afterwards. The README describes fixtures as modular, for managing small or parametrized long-lived test resources.
How do I use pytest parametrize?
Parametrization runs one test function against many input sets, and each set is collected and reported as its own item. The README groups parametrized fixtures together with small fixtures as the way long-lived test resources are managed.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pytest-dev-pytest)