JSON Assertions¶
Axiom.Json is the optional Axiom package for deterministic JSON assertions.
It focuses on:
- structural JSON equivalency
- simple JSON path existence checks
- simple scalar value-at-path checks
- simple object and array shape checks at a path
It does not add HTTP helpers, ASP.NET helpers, direct Newtonsoft.Json support, or a full JSONPath engine.
If your subject is HttpResponseMessage rather than raw JSON content, use HTTP and API assertions. Axiom.Http reuses Axiom.Json internally for response-body JSON checks.
Install¶
dotnet add package Axiom.Json
Use it alongside Axiom.Assertions:
using Axiom.Assertions;
using Axiom.Json;
Supported Inputs¶
The package supports:
- raw JSON
string JsonDocumentJsonElement
Examples:
using System.Text.Json;
using Axiom.Assertions;
using Axiom.Json;
var actualJson = """
{ "id": 1, "name": "Bob", "roles": ["admin", "author"] }
""";
var expectedJson = """
{ "roles": ["admin", "author"], "name": "Bob", "id": 1.0 }
""";
actualJson.Should().BeJsonEquivalentTo(expectedJson);
using var document = JsonDocument.Parse(actualJson);
document.Should().HaveJsonPath("$.roles[1]");
document.RootElement.Should().HaveJsonStringAtPath("$.name", "Bob");
Structural Equivalency¶
Use BeJsonEquivalentTo(...) and NotBeJsonEquivalentTo(...) when you want JSON-aware structural comparison instead of plain string equality.
using Axiom.Assertions;
using Axiom.Json;
var actualJson = """
{
"customer": {
"id": 7,
"active": true,
"roles": ["admin", "author"]
}
}
""";
var expectedJson = """
{
"customer": {
"roles": ["admin", "author"],
"active": true,
"id": 7.0
}
}
""";
actualJson.Should().BeJsonEquivalentTo(expectedJson);
actualJson.Should().NotBeJsonEquivalentTo("""
{ "customer": { "id": 9, "active": true, "roles": ["admin", "author"] } }
""");
Current semantics:
- object property order does not matter
- array order does matter
- missing properties and extra properties fail explicitly
- value-kind mismatches fail explicitly
- numeric comparison uses normalized JSON numeric values, so
1,1.0, and1e0are treated as equivalent
JSON Path Assertions¶
Axiom.Json uses a deliberately small path syntax:
- optional root marker:
$ - object-member traversal with
. - array-index traversal with
[index]
Examples:
$.customer.id$.customer.roles[0]items[1].sku
This is not a full JSONPath implementation. Property names that need escaping are out of scope for the current path model.
using Axiom.Assertions;
using Axiom.Json;
var json = """
{
"customer": {
"id": 7,
"name": "Bob",
"active": true,
"roles": ["admin", "author"],
"deletedAt": null
}
}
""";
json.Should().HaveJsonPath("$.customer.roles[1]");
json.Should().NotHaveJsonPath("$.customer.email");
json.Should().HaveJsonObjectAtPath("$.customer");
json.Should().HaveJsonArrayAtPath("$.customer.roles");
json.Should().HaveJsonArrayLengthAtPath("$.customer.roles", 2);
json.Should().HaveJsonPropertyCountAtPath("$.customer", 5);
json.Should().HaveJsonStringAtPath("$.customer.name", "Bob");
json.Should().HaveJsonNumberAtPath("$.customer.id", 7m);
json.Should().HaveJsonBooleanAtPath("$.customer.active", true);
json.Should().HaveJsonNullAtPath("$.customer.deletedAt");
Use HaveJsonObjectAtPath(...), HaveJsonArrayAtPath(...), and the count checks when the shape of the JSON at a path matters before checking scalar values inside it.
Invalid JSON¶
For raw JSON string subjects, invalid JSON fails clearly with an invalid JSON parse location in the failure message.
Invalid expected JSON passed as a raw string is treated as an invalid assertion argument and throws ArgumentException.
Current Limits¶
Axiom.Json is intentionally narrow:
System.Text.Jsoninputs plus raw JSON strings only- no direct
Newtonsoft.Jsonsupport - no HTTP or API-response helpers in this package; use
Axiom.HttpforHttpResponseMessage - no full JSONPath language
- array order is significant
For the full method list, see the Assertion Reference.