FluentAssertions 8.10: Equivalency Quality-of-Life Upgrades (Null-as-Empty, Better Diagnostics, Faster Unordered Matching)
FluentAssertions 8.10 looks small on paper, but it targets the exact place most test suites feel pain: equivalency comparisons and the diagnostics you rely on when they fail. If you use BeEquivalentTo heavily (DTOs, API contracts, nested object graphs), these changes reduce noise, improve failure readability, and speed up the slow cases.
Below are the four highlights and what they change in day-to-day test writing.
1) #3202 — Add ComparingNullCollectionsAsEmpty and ComparingNullStringsAsEmpty to BeEquivalentTo
What changed
FluentAssertions 8.10 adds two new equivalency options so null collections can match empty collections, and null strings can match empty strings.
ComparingNullStringsAsEmpty
Why this matters
In many systems, null vs empty is not a meaningful distinction. APIs omit fields, serializers produce nulls, and mapping layers can return null collections even when business logic treats them as empty. These mismatches used to create brittle tests or force pre-normalization.
Key detail: symmetric + nested object graphs
The behavior is symmetric (works on either side of the comparison) and it also applies inside nested object graphs. If a nested property is null on one side and empty on the other, it can still match when the option is enabled.
2) #3203 — Include original index in extraneous item failure messages
What changed
Equivalency failures for collections with extra items are now more actionable. Failure messages include the original index of each extraneous item in the subject.
Why this matters
When ordering is ignored and matching rules are complex, “extra item” failures are some of the most time-consuming to debug. With the original index included, you can jump straight to the problematic element—especially helpful for large collections produced by pipelines.
Practical impact
- Faster diagnosis of “why is there an extra item?”
- Easier correlation with upstream LINQ/filtering/join logic
- Less time printing entire collections to logs
3) #3188 — Significantly speed up BeEquivalentTo for large unordered collections
What changed
Performance is improved for unordered equivalency comparisons (especially with WithoutStrictOrdering()) on large collections.
Why this matters
Large unordered comparisons are a common source of slow tests. The main gain comes from replacing expensive permutation-based matching with a more scalable greedy strategy, plus allocation reductions and dry-run optimizations. Net effect: less time waiting on equivalency-heavy suites and fewer “it’s too slow to run locally” complaints.
Practical impact
- Faster unordered comparisons on large collections
- Better scalability as datasets grow
- Lower overhead from fewer allocations and less backtracking
4) #3187 — Fail with a descriptive error when path-based rules are used on value-semantic types
What changed
FluentAssertions fixes a confusing equivalency edge case: path-based rules like Including() y Excluding() that target members of value-semantic types were previously ignored silently.
Why this matters
Silent ignores are dangerous in tests: you think you’ve constrained the comparison, but the rule never applied. With 8.10, these cases now fail explicitly with a clear error explaining why the rule does not apply and how to resolve it. That’s a correctness win—especially for teams that rely on path-based configuration to keep assertions focused.
Practical impact
- No more silent “rule didn’t apply” surprises
- Clearer feedback when configuration is invalid
- More trustworthy equivalency rules in large suites
What to do next
If you’re upgrading to FluentAssertions 8.10, here’s a quick checklist:
- If your domain treats missing values as empty, consider enabling the null-as-empty options.
- If you compare large collections without strict ordering, expect faster runs and less test-suite drag.
- If you use path-based rules heavily, watch for newly surfaced configuration errors (that were previously ignored).
- Re-run equivalency-heavy tests and confirm failures are now easier to diagnose.
If your test suite leans on BeEquivalentTo, FluentAssertions 8.10 is a low-risk upgrade with high leverage: fewer brittle failures, clearer diagnostics, faster unordered comparisons, and stricter correctness around configuration rules.
FAQ
Does null-as-empty apply only at the top level?
No. The new options apply inside object graphs as well, so nested properties benefit too.
Is the null-as-empty comparison one-directional?
No. It works symmetrically on either side of the comparison.
Will the improved extraneous index diagnostics change assertion behavior?
No. This is a diagnostics improvement. The assertion still fails for the same reason; the failure message is simply more actionable.
What changed with unordered collection performance?
Unordered comparisons (for example, using WithoutStrictOrdering) are significantly faster on large collections due to a more scalable matching strategy and several allocation/dry-run optimizations.
Why do path-based rules now fail for value-semantic types?
Because those rules don’t apply to value-semantic types in the way most people expect. Instead of silently ignoring the rule, FluentAssertions now fails with a descriptive error so you can fix the configuration explicitly.