TracksSpecializations and Deep DivesTesting StrategiesUnit Testing Fundamentals(2 of 7)

Unit Testing Fundamentals

Unit tests verify that individual pieces of code work correctly in isolation. They're the foundation of a solid testing strategy — fast to run, easy to write, and precise about what they're checking.

What Is a Unit?

A unit is typically a single function or method. It takes inputs, does something, and produces outputs. Unit tests verify that given specific inputs, you get expected outputs.

The key word is isolated. A unit test shouldn't depend on databases, network calls, or other external systems. If your function calls an API, you mock that API call so the test runs without network access.

The Arrange-Act-Assert Pattern

Most unit tests follow a simple structure:

def test_calculate_discount():
    # Arrange - set up the test data
    price = 100
    discount_percent = 20
    
    # Act - call the function being tested
    result = calculate_discount(price, discount_percent)
    
    # Assert - verify the result
    assert result == 80

Arrange: Prepare everything the test needs — input values, mock objects, test fixtures.

Act: Call the function or method you're testing.

Assert: Verify the result matches expectations.

This pattern makes tests readable. Anyone can understand what's being tested and what the expected behavior is.

Best Practices

One assertion per test (usually). Each test should verify one specific behavior. If a test fails, you know exactly what broke.

Use descriptive names. test_calculate_discount_applies_percentage tells you more than test_discount. When tests fail, good names explain what went wrong.

Test edge cases. What happens with zero? Negative numbers? Empty strings? Null values? Edge cases are where bugs hide.

Keep tests independent. Tests shouldn't depend on each other or run in a specific order. Each test should set up its own data and clean up after itself.

Mocking Dependencies

When your function depends on external services, mock them:

def test_send_notification(mocker):
    # Mock the email service so we don't send real emails
    mock_send = mocker.patch('email_service.send')
    
    # Call the function under test
    notify_user(user_id=123, message="Hello")
    
    # Verify the email service was called correctly
    mock_send.assert_called_once_with(
        to="user123@example.com",
        body="Hello"
    )

Mocks let you test your code's logic without testing the external service. They also let you simulate error conditions — what happens when the email service is down?

See More

Further Reading

Last updated December 26, 2025

You need to be signed in to leave a comment and join the discussion