If you're looking to create tests for your application, there's 2 well-known libraries you've likely come across: Pytest and unittest.

In my experience, however, most developers don't use unittest for a number of reasons, with the main reason being that Pytest offers a significant more amount of testing capabilities.

Understanding different kinds of tests

Writing tests for your code is essential, especially with how quick we're able to develop apps using AI. There's 4 types of tests:

  • End-to-End: tests that simulate a real user going through your app from start to finish, usually in an environment that looks like production. This is the largest scoped test.

  • Integration: tests that check whether different parts of your app work together correctly - your code talking to a database, or an API calling another service.

  • Functional: tests that check your app meets a specific requirement or spec, often spanning several units and services at once - think "can a user reset their password," not "does this one function return the right hash."

  • Unit: tests that isolate one function or method in complete isolation from the rest of the app, and check that it returns the right output for a given input. This is the lowest and smallest-scoped type of test.

So, when building your application you should be thinking of how you’d write these tests and where you’d write them.

Unittest capabilities

Unittest gives you the basics you'd expect from a testing framework:

  • Methods to setup and tear down before and after each test

  • A mocking library to test a database, API, or file system.

  • Assertion methods to check equality, truth, existence, etc.

  • Built-in test discovery via python -m unittest discover

The best part about unittest is that it’s built into the standard library, so you don’t need to use uv or pip and manage an environment.

One of the biggest drawbacks about unittest is that it’s relatively difficult to write anything but unit tests.

Pytest capabilities

Pytest does everything unittest does and enables users to write functional, end-to-end, and integration tests:

  • Plain assert statements instead of a dozen assert methods.

  • Fixtures which is significantly more flexible with setup and tear down your testing methods.

  • Built-in parametrization, so you can run the same test against a list of inputs without copy-pasting the test.

  • A plugin ecosystem (pytest-cov, pytest-mock, pytest-xdist) to extend core functionality of Pytest.

Code comparison

When looking at the code side-by-side for testing an add function, we see that unittest takes more of an object-oriented approach:

import unittest

def add(a, b):
    return a + b

# Tests for the function `add`
class TestAdd(unittest.TestCase):
    def setUp(self):
        self.a = 2
        self.b = 3

    def test_add_positive_numbers(self):
        self.assertEqual(add(self.a, self.b), 5)

    def test_add_negative_numbers(self):
        self.assertEqual(add(-2, -3), -5)

    def test_add_zero(self):
        self.assertEqual(add(0, 5), 5)

    def test_add_returns_int(self):
        self.assertIsInstance(add(self.a, self.b), int)

if __name__ == "__main__":
    unittest.main()

Whereas Pytest (in this case) can take more of a functional approach:

def add(a, b):
    return a + b

# Tests for the function `add`
def test_add_positive_numbers():
    assert add(2, 3) == 5

def test_add_negative_numbers():
    assert add(-2, -3) == -5

def test_add_zero():
    assert add(0, 5) == 5

def test_add_returns_int():
    assert isinstance(add(2, 3), int)

Which is better?

While it's very quick and easy to say “Pytest is the right package!”, remember these are tools with their own advantages:

  • Pytest advantages: less boilerplate, fixtures, parametrization, plugins, and readable failure output. For almost any new project, this is what I'd reach for.

  • Unittest advantages: it's in the standard library, so there's nothing to install. It’s great for quick, small apps and to handle cases where you’re rewriting code and functionality.

Happy coding!

📧 Join the Python Snacks Newsletter! 🐍

Want even more Python-related content that’s useful? Here’s 3 reasons why you should subscribe the Python Snacks newsletter:

  1. Get Ahead in Python with bite-sized Python tips and tricks delivered straight to your inbox, like the one above.

  2. Exclusive Subscriber Perks: Receive a curated selection of up to 6 high-impact Python resources, tips, and exclusive insights with each email.

  3. Get Smarter with Python in under 5 minutes. Your next Python breakthrough could just an email away.

You can unsubscribe at any time.

Interested in starting a newsletter or a blog?

Do you have a wealth of knowledge and insights to share with the world? Starting your own newsletter or blog is an excellent way to establish yourself as an authority in your field, connect with a like-minded community, and open up new opportunities.

If TikTok, Twitter, Facebook, or other social media platforms were to get banned, you’d lose all your followers. This is why you should start a newsletter: you own your audience.

This article may contain affiliate links. Affiliate links come at no cost to you and support the costs of this blog. Should you purchase a product/service from an affiliate link, it will come at no additional cost to you.