Validating Json Data Edit on GitHub


Note! This feature was added in Storyteller 4.2

While it may be easier in many cases to deserialize the Json string into a .Net object and validate against that, in other cases you may only have the raw Json. Fortunately, Storyteller now includes a base class called JsonComparisonFixture that you can subclass in your Storyteller specification project to verify the expected values within a JSON document. Behind the scenes, JsonComparisonFixture heavily uses the JSONPath support in Newtonsoft.Json to pick out values within the Json structure.

For a quick example, here's a simplistic sample that verifies the contents of a simple Address Json document:


public class AddressJsonFixture : JsonComparisonFixture
{
    public override void SetUp()
    {
        // Before you call any assertions, you'll need
        // to attach the Json string to the current
        // JsonComparisonFixture
        var json = fetchJson();
        StoreJson(json);
    }

    private string fetchJson()
    {
        return "{\"city\": \"Austin\", \"distance\": \"5\"}";
    }

    public IGrammar CityIs()
    {
        return CheckJsonValue<string>("$.city", "The city should be {city}");
    }

    public IGrammar DistanceIs()
    {
        return CheckJsonValue<int>("$.distance", "The distance should be {distance}");
    }
}

Checking a Single Typed Value

To verify a single value in a Json document, use the CheckJsonValue() method shown below to create a declarative grammar:


public IGrammar CheckValue()
{
    return CheckJsonValue<int>("$.number", "The current number should be {number}");
}

Simple types are extracted from the Json document, parsed to the declared type, and then compared. String's just do an exact comparison to the raw Json value. Finally, any other type is deserialized via Newtonsoft.Json from the Json object matching the specified JSONPath. An example of this is verifying an array of integers like this:


public IGrammar CheckNumberArray()
{
    return CheckJsonValue<int[]>("$.numbers", "The number array should be {numbers}");
}

In usage, that grammar looks like this in a sample specification:

Checking Json Values in a Table

As a shortcut, if you're fine exposing JSONPath expressions directly into your Storyteller specification visualization, you can use this built in grammar as shown in this specification:

In the underlying markdown file, the usage of the Check Json Values grammar used above looks like this:

# Simple Value Checks

[SampleJson]
|> CheckJsonValues
    [table]
    |path   |returnValue|
    |$.color|red        |
    |$.order|1          |
    |$.color|wrong      |
    |$.order|wrong      |


Set Verification of Set Elements

JsonComparisonFixture also contains a way to utilize Storyteller's set verification capability within Json documents. Here's a sample grammar that uses this functionality:


public IGrammar CheckPeople()
{
    // "$.children" designates the JSONPath to the json array
    return VerifyChildElementSet("$.children").Titled("The people should be")
        .Compare(_ =>
        {
            // Checking values within the elements of the Json array
            // The first argument is a JSONPath relative to each element of the array
            // The second argument is necessary to give Storyteller a name for
            // the expected data
            _.Check<string>("$.first", "first");
            _.Check<string>("$.last", "last");
            _.Check<int>("$.age", "age");

            // Arrays are valid here, and you can customize the Cell with
            // the fluent interface shown below
            _.Check<int[]>("$.numbers", "numbers").Header("the numbers");
            _.Check<string>("$.address.city", "city");
        });
}

Which is going to look like a normal set verification table in the results of a specification:

Deep Assertions

To do a deep assertion of an element within the Json document to an expected Json structure, you can use the assertDeepJsonEquals() method to do a semantic comparison (using Newtonsoft.Json behind the scenes):


[FormatAs("Deep equals check of {name} and {age}")]
public void CompareChild(string name, int age)
{
    var dict = new Dictionary<string, string> {{"name", name}, {"age", age.ToString()}};

    var json = JsonConvert.SerializeObject(dict);
    assertDeepJsonEquals("child", json);
    
}

If the comparison fails, you'll see the actual and expected values in the specification results:

Other Helpers

JsonComparisonFixture includes a couple utility methods and properties:

  • deserialize<T>(path) -- deserializes the Json object or value found at the JSONPath to the designated type T.
  • JsonSerializerSettings -- use this to control the Newtonsoft.Json serialization within the current Fixture
  • StoreJson(json) -- load the Json data you want to verify
  • JObject -- if you're familiar with Newtonsoft's DOM model, you can directly utilize the topmost JObject node for the current Json document