JSON-native asserts and sharper object graph comparisons
Fluent Assertions 8.7.0 is here, and it’s a meaningful step forward for teams testing JSON APIs and deep object graphs. This release brings first-class System.Text.Json support, upgrades to BeEquivalentTo precision, and a new way to validate exception messages. The net effect: fewer brittle diffs, more resilient test suites, and clearer intent in your specs.
Why it matters
- JSON-native assertions – Directly assert structure, types, and values on JsonNode and JsonArray.
- Sharper object graph equivalence – Fine-tune strict typing, member selection, and mapping for DTO vs. domain comparisons.
- Cleaner exception specs – Use WithoutMessage to guarantee an exception message doesn’t match unwanted patterns.
JSON support
JSON payloads are now first-class citizens in your tests.
var node = JsonNode.Parse("{ \"name\": \"Product\", \"price\": 99.99 }");
node.Should().BeEquivalentTo(new { name = "Product", price = 99.99 });
node.Should().HaveProperty("name").Which.ToString().Should().Be("Product");
node.Should().NotHaveProperty("code");
JsonArray array = JsonNode.Parse("[1, 2, 3]")!.AsArray();
array.Should().NotBeEmpty();
Helpers like BeString, BeNumeric, BeBool, BeUtcDate, and BeAnArray make intent obvious at a glance. If casing differs, use IgnoringJsonPropertyCasing().
Object graph equivalence upgrades
BeEquivalentTo gets more precise, giving you surgical control over equivalence checks.
- Strict typing controls
- WithStrictTyping → enforce across the whole graph
- WithStrictTypingFor → target specific paths
- WithoutStrictTyping → override globally
- Runtime vs. declared types
- PreferringRuntimeMemberTypes() or PreferringDeclaredMemberTypes()
- Member selection & mapping
- Exclude noisy properties
- Align mismatched names with WithMapping
- Enums by name
- ComparingEnumsByName() avoids numeric mismatches
- Collections
- AllBeEquivalentTo makes asserting homogeneous sets trivial
Exception assertions
A new option: WithoutMessage. This ensures an exception’s message does not contain a given wildcard pattern—handy for privacy requirements or sanitizing user-facing error messages.
Practical test design tips
- Start strict where regressions matter most; keep the rest flexible.
- Use mapping to stabilize DTO/domain differences without rewriting models.
- Prefer runtime member types when dealing with proxies or dynamic types.
- Use JSON-native asserts for API tests; keep BeEquivalentTo for structural comparisons.
Release rollup (8.7 → 8.1)
Recent highlights worth noting:
- 8.6.0 – Value.ThatMatches and ThatSatisfies for inline assertions.
- 8.5.0 – WithStrictTyping and WithStrictTypingFor.
- 8.4.0 – ExcludingMembersNamed and new exception helpers.
- 8.3.0 – Better date/time and exception message rendering.
- 8.1.x – Fixes for dictionary formatting, NRT annotations, async task handling.
Get started
- Upgrade to 8.7.0 in your test project.
- Review BeEquivalentTo usages — add strict typing where intent matters.
- Switch to JSON-native asserts for clearer, more resilient API tests.