Python Unit Testing with unittest And pytest

Unit testing is an essential practice in software development that helps ensure your code works as expected. Python provides two popular testing frameworks: unittest and pytest. In this tutorial, we will explore both frameworks, showing you how to write tests, run them, and understand the test results.

1. Introduction to Unit Testing

Unit testing involves writing test cases to check the functionality of specific parts of your code, usually individual functions or methods. Python provides built-in libraries for unit testing, with unittest being the standard library and pytest being an external but widely used testing framework.

2. Unit Testing with unittest

The unittest module is Python’s built-in framework for unit testing. It uses test cases, assertions, and test runners to test the behavior of your code. Here’s how to get started with unittest:

2.1 Writing Test Cases with unittest

First, let’s create a simple Python function that we’ll test. Here’s an example of a function that adds two numbers:

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

Try It Now

Now, let’s write a test case for this function using unittest:

import unittest

class TestMathOperations(unittest.TestCase):
    
    def test_add(self):
        # Test addition function
        self.assertEqual(add(2, 3), 5)
        self.assertEqual(add(-1, 1), 0)
        self.assertEqual(add(0, 0), 0)

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

Try It Now

In the code above:

  • TestMathOperations is a test case class that inherits from unittest.TestCase.
  • test_add is a test method that uses the assertEqual method to check whether the result of the add function is correct.
  • unittest.main() runs the tests when the script is executed.

2.2 Running the Tests

To run the tests, simply execute the script:

python test_script.py

Try It Now

If the tests pass, you’ll see an output indicating success. If there are any failures, the output will show the error messages for each failed test.

3. Unit Testing with pytest

pytest is an external library that offers more advanced features, including simpler syntax, better output formatting, and more powerful assertions. To install pytest, run:

pip install pytest

Try It Now

3.1 Writing Test Cases with pytest

Let’s rewrite our test case using pytest. The syntax in pytest is simpler and doesn’t require creating classes that inherit from unittest.TestCase:

# test_math_operations.py
import pytest
from math_operations import add  # Assuming add function is in math_operations.py

def test_add():
    assert add(2, 3) == 5
    assert add(-1, 1) == 0
    assert add(0, 0) == 0

Try It Now

In this example, we simply define the test_add function and use the assert statement to check that the add function behaves correctly. No need to create test case classes!

3.2 Running the Tests

To run the tests with pytest, simply use the following command:

pytest test_math_operations.py

Try It Now

When you run pytest, it will automatically find and run any functions prefixed with test_. If all tests pass, you’ll see a success message. If any tests fail, pytest provides detailed information about the failure.

4. Key Features of unittest vs pytest

Both unittest and pytest provide similar functionality, but they have some differences:

  • Syntax: pytest offers simpler syntax without requiring test case classes, while unittest requires creating classes that inherit from unittest.TestCase.
  • Assertions: pytest uses the simple assert statement, while unittest provides methods like assertEqual, assertTrue, and others.
  • Test Discovery: pytest automatically discovers tests by looking for functions prefixed with test_, whereas unittest requires you to manually call unittest.main().
  • Advanced Features: pytest offers more advanced features, such as fixtures, parameterized tests, and better reporting, while unittest is more basic and integrated into Python’s standard library.

5. Running Tests in a Test Suite

In both unittest and pytest, you can organize your tests into test suites. In unittest, you can create a test suite by combining multiple test cases:

import unittest
from test_add import TestMathOperations
from test_subtract import TestSubtractOperations

# Create a test suite
def suite():
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestMathOperations))
    suite.addTest(unittest.makeSuite(TestSubtractOperations))
    return suite

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())

Try It Now

In pytest, test discovery and execution are handled automatically, so running all tests in a folder is as simple as:

pytest tests/

Try It Now

Conclusion

Unit testing is an essential part of maintaining reliable code. Both unittest and pytest are powerful tools for writing and running tests. While unittest is Python’s built-in framework and good for simple testing, pytest offers more flexibility and advanced features.