JSON Assertions¶
Axiom.Json is the optional Axiom package for deterministic JSON assertions.
It focuses on a small first wave:
- structural JSON equivalency
- simple JSON path existence checks
- simple scalar value-at-path checks
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 first wave 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¶
The first wave 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 this first wave.
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().HaveJsonStringAtPath("$.customer.name", "Bob");
json.Should().HaveJsonNumberAtPath("$.customer.id", 7m);
json.Should().HaveJsonBooleanAtPath("$.customer.active", true);
json.Should().HaveJsonNullAtPath("$.customer.deletedAt");
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.
First-Wave Limits¶
Axiom.Json in 2.1.0 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.