pytest vs unittest: Choosing a Python Testing Framework

How pytest and Python’s built-in unittest module differ, and why most teams choose pytest despite unittest requiring no installation

unittest ships with every Python installation. pytest requires pip install pytest. That one-line installation cost is nearly the only thing unittest has going for it in this comparison.

Assertion syntax

unittest uses class-based test cases with specific assertion methods:

import unittest

class TestMath(unittest.TestCase):
    def test_addition(self):
        self.assertEqual(2 + 2, 4)

pytest uses plain Python assert statements, with no test-case class required:

def test_addition():
    assert 2 + 2 == 4

pytest’s assertion introspection is the bigger practical difference: when a plain assert fails, pytest rewrites the bytecode to show you the actual values on both sides of the comparison in the failure output. unittest’s assertEqual gives you a similar message, but only for the specific assertion methods it defines — a plain assert inside a unittest test case fails with no useful detail at all.

Fixtures vs setUp/tearDown

unittest handles test setup and teardown through setUp()/tearDown() methods on the test class, run before and after every test in that class. pytest’s fixture system is more flexible — fixtures can be shared across multiple test files, scoped to run once per session or once per test, and composed by simply requesting one fixture as a parameter of another.

Running unittest tests with pytest

You don’t have to choose exclusively — pytest can discover and run unittest-style TestCase classes without modification, which is why many codebases migrate gradually: keep existing unittest.TestCase tests running as-is, write all new tests in pytest’s plain-function style, and run the whole suite with the pytest command either way.

Which one to use

For a new project: pytest, without much debate — better failure messages, less boilerplate, a fixture system that scales better as a suite grows, and a large plugin ecosystem (coverage reporting, parallel test runs, mocking helpers) built around it. Reach for plain unittest specifically when you can’t add a dependency at all, or you’re working in an existing unittest-based codebase where a full migration isn’t worth the churn.

Frequently Asked Questions

What’s the main difference between pytest and unittest?

unittest ships with every Python installation and uses class-based test cases with specific assertion methods. pytest requires installation but uses plain assert statements and rewrites failure output to show the actual values being compared.

Can pytest run unittest tests?

Yes — pytest can discover and run unittest-style TestCase classes without modification, which is why many codebases migrate gradually rather than rewriting an entire suite at once.

Which one should you use for a new project?

pytest, without much debate — better failure messages, less boilerplate, and a fixture system that scales better as a suite grows. Use plain unittest only when you can’t add a dependency at all.

How do pytest fixtures differ from unittest’s setUp/tearDown?

unittest’s setUp()/tearDown() run before and after every test in a class. pytest’s fixtures are more flexible — they can be shared across multiple test files, scoped per session or per test, and composed by requesting one fixture as a parameter of another.