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

Testing Immutable Data Structures

Verify the logic of record-based objects and transformation pipelines.

Testing Immutable Data Structures

In this lesson, you will learn how to verify the integrity of C# record types and ensure that your functional transformation pipelines behave predictably without unintended side effects.

When working with immutable data structures, your testing strategy shifts from verifying state changes to verifying transformation results. Because a record cannot be modified after instantiation, you aren't testing setters; you are testing that a method correctly returns a new instance with the expected data, while leaving the original instance untouched.

Verifying Transformation Pipelines

Consider a transformation pipeline that calculates discounts on an order. With immutable records, you verify that the source object remains identical after the operation and that the output object reflects the correct calculations.

public record Order(decimal Total, decimal Discount);

[Fact]
public void ApplyDiscount_ReturnsNewOrder_WithCorrectCalculation()
{
    // Arrange
    var original = new Order(100m, 0m);
    var service = new OrderProcessor();

    // Act
    var updated = service.ApplyDiscount(original, 0.10m);

    // Assert
    // 1. Verify the result is correct
    Assert.Equal(90m, updated.Total);
    
    // 2. Verify immutability (The original instance is untouched)
    Assert.Equal(100m, original.Total);
    
    // 3. Ensure they are distinct instances
    Assert.NotSame(original, updated);
}

Why This Matters

When your logic relies on functional chains—where you map, filter, or reduce data—the most common bug isn't a corrupted object; it’s a "leaked mutation." If a method accidentally modifies a property of a record, it breaks the contract of immutability and introduces unpredictable behavior elsewhere in the system.

By testing that the original instance remains in its initial state, you gain a high degree of confidence that your domain model remains pure. Furthermore, when testing deep transformation pipelines, focus on asserting the equality of the final record state. Because records implement value-based equality, you can compare the entire object graph using Assert.Equal(expected, actual), which simplifies your assertions significantly compared to checking individual properties of mutable classes.

Key Takeaway: Testing immutability means asserting that transformations return a new, correct instance while proving that the original reference remains strictly unchanged.