Skip to content

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
  • JsonDocument
  • JsonElement

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, and 1e0 are 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.Json inputs plus raw JSON strings only
  • no direct Newtonsoft.Json support
  • no HTTP or API-response helpers in this package; use Axiom.Http for HttpResponseMessage
  • no full JSONPath language
  • array order is significant

For the full method list, see the Assertion Reference.