web-dev-qa-db-ja.com

JsonReaderユニットがカスタムJsonConverterをテストする方法

同じAPIの異なるバージョンによって返される異なるJson形式を処理するために、カスタムJsonConverterを作成しました。 1つのアプリが他のいくつかのアプリにリクエストを送信しますが、どの形式が返されるかわからないため、JsonConverterがこれを処理し、正常に機能しているようです。 Newtonsoft.Jsonオブジェクトの一部(主にJsonReader)をモックアウトするのに役立つリソースが見つからない場合を除いて、プロジェクトに単体テストを追加する必要があります。

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jsonValue = JObject.Load(reader);
        if(jsonValue == null)
        {
            return null;
        }

        var responseData = ReadJsonObject(jsonValue);
        return responseData;
    }

    [TestMethod]
    public void ReadJsonReturnNullForNullJson()
    {
        var converter = new DataConverter();

        _mockJsonReader.Setup(x => x.Value).Returns(null);

        var responseData = converter.ReadJson(_mockJsonReader.Object, typeof(ProbeResponseData), null, _mockJsonSerializer.Object);

        Assert.IsNull(responseData);
    }

一部のコードがReadJsonメソッドから削除されました。実際のjsonの値(この場合はnull値)を返すようにJsonReaderをセットアップしようとしていますが、他の単体テストでは実際のJson(JObject)が必要です。単体テストを実行すると、「Newtonsoft.JsonReaderException:JsonReaderからのJObjectの読み取りエラー。パス ''」が表示されます。

9
Casey O'Brien

の用法 DeserializeObject<T>は、内部でReadJsonのオーバーライドを呼び出します。

[TestMethod]
public void ReadJsonVerifyTypeReturned()
{
    var testJson = CreateJsonString();

    var result = JsonConvert.DeserializeObject<ProbeResponseData>(testJson);
    var resultCheck = result as ProbeResponseData;

    Assert.IsNotNull(resultCheck);
}
6
Jeff Dalley

JsonConvertまたはJsonSerializerを直接使用するとテストできますが、コンバーターのテストをもう少し直接行う必要があります。たとえば、デシリアライザーを呼び出したときにJSON.NETが期待どおりに動作することを保証することはできませんが、実際にテストしたいのはです。カスタムコンバーター-JSON.NETがそれを使って行うことはあなたのコントロールの外にあります。

この例を考えてみましょう。

public readonly struct UserId
{
  public static readonly UserId Empty = new UserId();

  public UserId(int value)
  {
    Value = value;
    HasValue = true;
  }

  public int Value { get; }
  public bool HasValue { get; }
}

intに裏打ちされたこの構造体があります。特定のJSONnumber値をint-> UserIdとして逆シリアル化したい。そこで、カスタムコンバーターを作成します。

public class UserIdConverter
{
  public override bool CanConvert(Type objectType) => objectType == typeof(UserId);

  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  {
    int? id = serializer.Deserialize<int?>(reader);
    if (!id.HasValue)
    {
      return UserId.Empty;
    }

    return new UserId(id.Value);
  }
}

このインスタンスではWriteJsonの実装をスキップしましたが、ロジックは同じです。

私は次のようにテストを書きます:

[Fact]
public void UserIdJsonConverter_CanConvertFromJsonNumber()
{
    // Arrange
    var serialiser = new JsonSerializer();
    var reader = CreateJsonReader("10");
    var converter = new UserIdJsonConverter();

    // Act
    var result = converter.ReadJson(reader, typeof(UserId), null, serialiser);

    // Assert
    Assert.NotNull(result);
    Assert.IsType<UserId>(result);

    var id = (UserId)result;
    Assert.True(id.HasValue);
    Assert.Equal(10, id.Value);
}

private JsonTextReader CreateJsonReader(string json)
    => new JsonTextReader(new StringReader(json));

そうすることで、純粋にReadJsonメソッドを中心にテストを作成し、期待どおりに動作することを確認できます。 さらに進んでJsonReaderJsonSerializerなどの要素をモックして、異なる前提条件を作成する可能性があるため、さまざまなシナリオをテストできます。

完全な逆シリアル化プロセスを実行するためにJsonConvertまたはJsonSerializerに依存する場合の問題は、主に制御できない他のロジックを導入していることです。つまり、逆シリアル化によって、JSON.NETが実際に異なる決定を行い、カスタムコンバーターが使用されない場合はどうなりますか?テストはJSON.NET自体のテストを担当しませんが、カスタムコンバーターは実際に何を行いますか。

1
Matthew Abbott

これを使用して、変換された結果を確認してください。

DeserializedType result = JsonConvert.DeserializeObject<DeserializedType>(json, new Converter(parms));

ドキュメントから

0
Petr Šebesta

コンバーターをテストするには、コンバーターのリストに含まれている必要があります。 JsonConverterAttributeを使用した場合は自動的に機能しますが、使用しなかった場合は次のように実行できます。

var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new MyJsonConverter());

var serializer = JsonSerializer.Create(serializerSettings);

var jObject = JObject.Parse(myString);
var result = jObject.ToObject<MyObject>(serializer);
0
jsgoupil

カスタムコンバーターの内部動作を知らなくても、モックの代わりにテストダブルを作成できますか?

public class JsonReaderThatReturnsNull : JsonReader
{
    public override bool Read()
    {
        return true;
    }

    public override object Value => null;
}
0
Scott Hannen