Course contentsShow
← C#
Lesson 1723 of 1,90815. Software Quality and TestingFree lesson

Isolation of Cross-Cutting Concerns

Use decorators or proxies to test business logic without interference from logging or auth.

In this lesson, you will learn how to isolate cross-cutting concerns like logging and authentication using the Decorator pattern to ensure your business logic remains testable in complete isolation.

The Problem: The "Mixed-Bag" Service

When you bake cross-cutting concerns directly into your business services, your unit tests become bloated. If a PaymentProcessor handles transaction logic, user authorization, and logging, testing the logic requires mocking the logger and the auth provider just to perform a simple calculation. This violates the Single Responsibility Principle and complicates test setup.

The Solution: Decorators for Isolation

By using the Decorator pattern, you can separate the "core" logic from the "infrastructure" logic. You define an interface for your business operation and create two implementations: one for the core logic and one (the decorator) that handles the extra concerns.

Consider this IPaymentService:

public interface IPaymentService {
    void Process(decimal amount);
}

// The Core: Only contains business logic
public class PaymentService : IPaymentService {
    public void Process(decimal amount) { /* Core logic */ }
}

// The Decorator: Adds cross-cutting concerns
public class LoggingPaymentDecorator : IPaymentService {
    private readonly IPaymentService _inner;
    public LoggingPaymentDecorator(IPaymentService inner) => _inner = inner;

    public void Process(decimal amount) {
        // Logging logic here
        _inner.Process(amount);
    }
}

Why this improves Testing

Because the PaymentService is now "pure," your unit tests don’t need to worry about loggers or authentication headers. You simply instantiate PaymentService directly in your test suite and verify its behavior.

If you need to test the decorator specifically, you can mock IPaymentService and verify that the decorator calls the inner service correctly. This separation means you are no longer testing the framework's logging capabilities or your auth middleware whenever you change a line of business code. You isolate the concerns into distinct, testable classes, making your test suite faster, cleaner, and significantly easier to maintain.

Key Takeaway: By wrapping business services in decorators, you move cross-cutting infrastructure out of your domain logic, allowing you to unit test core functionality without the overhead of mocking secondary concerns.