Back to Repositories

Testing Observer Pattern Implementation in python-patterns

This test suite validates the Observer pattern implementation in Python, focusing on testing the attachment, detachment, and notification mechanisms between subjects and observers. It verifies the core functionality of the observer pattern through comprehensive unit tests.

Test Coverage Overview

The test suite provides thorough coverage of the Observer pattern’s core operations.

Key areas tested include:
  • Observer attachment and detachment functionality
  • Data change notification system
  • Observer list management
  • State change propagation to multiple observers
Edge cases covered include verifying single notification per data change and proper observer list maintenance.

Implementation Analysis

The testing approach utilizes pytest fixtures and mocking to isolate and verify observer pattern behaviors. The implementation leverages unittest.mock for tracking method calls and pytest’s fixture system for test setup.

Technical patterns include:
  • Fixture-based test data initialization
  • Mock objects for verification
  • Context manager usage for patch operations
  • Assertion-based validation

Technical Details

Testing tools and configuration:
  • pytest as the primary testing framework
  • unittest.mock for method call tracking
  • Mock and patch utilities for behavior verification
  • Fixture-based test data management
  • Assert statements for validation

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through focused test cases and clear organization. Notable practices include:
  • Isolated test cases with clear purposes
  • Effective use of fixtures for setup
  • Mock objects for controlled testing
  • Clear test naming conventions
  • Proper separation of concerns

faif/python-patterns

tests/behavioral/test_observer.py

            
from unittest.mock import Mock, patch

import pytest

from patterns.behavioral.observer import Data, DecimalViewer, HexViewer


@pytest.fixture
def observable():
    return Data("some data")


def test_attach_detach(observable):
    decimal_viewer = DecimalViewer()
    assert len(observable._observers) == 0

    observable.attach(decimal_viewer)
    assert decimal_viewer in observable._observers

    observable.detach(decimal_viewer)
    assert decimal_viewer not in observable._observers


def test_one_data_change_notifies_each_observer_once(observable):
    observable.attach(DecimalViewer())
    observable.attach(HexViewer())

    with patch(
        "patterns.behavioral.observer.DecimalViewer.update", new_callable=Mock()
    ) as mocked_update:
        assert mocked_update.call_count == 0
        observable.data = 10
        assert mocked_update.call_count == 1