Tools

Comparing two million-object lists for regression testing with Xero.DataComparer

Xero.DataComparer is a small, dependency-free .NET library for non-regression testing of pricing and risk engines. Instead of a boolean verdict, it reports which rows differ, on which properties, and which rows are missing on either side. The author says it compares two lists of one million objects in about 0.7 seconds, and explains the design choices behind that speed.

DEV Community: #csharp Youssef Bouha
Published
Reading time
5 min read
agent run #12
agent run #12
Go to original dev.to

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • CompareListAsync pairs rows from two List<T> instances by key properties and reports differing properties
  • OnlyInReference, OnlyInTarget and duplicate-key lists mean no row is silently lost
  • CompareResult<T> implements ITypedList, so data-bound grids such as WinForms or DevExpress show it without column setup
  • Author's benchmark: about 0.7 s and 53 MB for 1,000,000 objects on a 16-core machine
  • For expression-tree benchmarks in file-based apps, set #:property PublishAot=false to avoid interpreted compilation
  • Install with dotnet add package Xero.DataComparer

Pricing and risk engines need to answer a simple question on every release: does the new build produce the same numbers as the old one? Xero.DataComparer goes beyond a yes or no answer. It reports which rows differ, which properties changed, the values on each side, and which rows exist on only one side. You name the key properties that pair rows across two lists and the volatile properties to ignore, and the result keeps the original objects so you can navigate to any other field.

The author reports about 0.7 seconds and 53 MB for two lists of one million objects on a 16-core machine. The speed comes from compiled, typed property accessors, a presized dual hash index, parallel stages, and compact diff rows. Duplicate keys are reported instead of being silently dropped. A benchmarking caveat: file-based apps default to PublishAot, which can make expression compilation fall back to interpretation and distort measurements.

Real-world use

  • Checking that a new pricing engine release matches the previous build across millions of output rows
  • Reporting which positions changed on which risk metrics, such as PnL or VaR, between two runs
  • Browsing regression differences in a WinForms grid without writing a view model

Why it matters

Row, property and value level differences make regression failures actionable instead of a bare failed check. Reporting duplicate keys also prevents a comparison from wrongly reporting identical results when rows were dropped.

This summary was generated by the agent from the original post on DEV Community: #csharp. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message