Python by example

Testing in Python

Testing is essential for ensuring your code works as expected. Python provides several built-in modules for testing, with unittest being the most common, but there exist other libraries like pytest that are widely used, which offer more features and a simpler syntax.

Basic Unit Test

The unittest module provides a framework for writing and running tests. Here’s a simple example:

import unittest

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

class TestAddFunction(unittest.TestCase):
    def test_add_positive_numbers(self):
        self.assertEqual(add(1, 2), 3)
    
    def test_add_negative_numbers(self):
        self.assertEqual(add(-1, -1), -2)

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

Common Assertions

The unittest module provides several assertion methods:

import unittest

class TestAssertions(unittest.TestCase):
    def test_assertions(self):
        self.assertEqual(1 + 1, 2)          # Check if two values are equal
        self.assertNotEqual(1 + 1, 3)        # Check if two values are not equal
        self.assertTrue(1 < 2)               # Check if a value is True
        self.assertFalse(1 > 2)              # Check if a value is False
        self.assertIn(1, [1, 2, 3])          # Check if a value is in a sequence
        self.assertNotIn(4, [1, 2, 3])       # Check if a value is not in a sequence
        self.assertIsNone(None)              # Check if a value is None
        self.assertIsNotNone(1)              # Check if a value is not None

Using pytest

pytest is a popular alternative to unittest that is simpler to use. Install it using pip install pytest:

# test_example.py
def add(a, b):
    return a + b

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

Run the test with the command pytest test_example.py.

Test Fixtures

Test fixtures are special setup functions that prepare the testing environment. Unlike regular variables or functions, fixtures are managed by the testing framework and can be easily shared between tests:

import pytest

@pytest.fixture
def sample_data():
    return [1, 2, 3, 4, 5]

def test_sum(sample_data):
    assert sum(sample_data) == 15

def test_length(sample_data):
    assert len(sample_data) == 5

Mock Objects

The unittest.mock module is used to replace parts of your system under test:

from unittest.mock import Mock

# Create a mock object
mock_database = Mock()
mock_database.get_user.return_value = {"id": 1, "name": "Alice"}

# Use the mock object
user = mock_database.get_user(1)
print(user["name"])  # Output: Alice

# Verify the mock was called correctly
mock_database.get_user.assert_called_once_with(1)

Test Coverage

You can check how much of your code is covered by tests using the coverage module:

pip install coverage
coverage run -m pytest test_example.py
coverage report
Next example: Time