同じ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の読み取りエラー。パス ''」が表示されます。
の用法 DeserializeObject<T>
は、内部でReadJsonのオーバーライドを呼び出します。
[TestMethod]
public void ReadJsonVerifyTypeReturned()
{
var testJson = CreateJsonString();
var result = JsonConvert.DeserializeObject<ProbeResponseData>(testJson);
var resultCheck = result as ProbeResponseData;
Assert.IsNotNull(resultCheck);
}
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
メソッドを中心にテストを作成し、期待どおりに動作することを確認できます。 さらに進んで、JsonReader
やJsonSerializer
などの要素をモックして、異なる前提条件を作成する可能性があるため、さまざまなシナリオをテストできます。
完全な逆シリアル化プロセスを実行するためにJsonConvert
またはJsonSerializer
に依存する場合の問題は、主に制御できない他のロジックを導入していることです。つまり、逆シリアル化によって、JSON.NETが実際に異なる決定を行い、カスタムコンバーターが使用されない場合はどうなりますか?テストはJSON.NET自体のテストを担当しませんが、カスタムコンバーターは実際に何を行いますか。
これを使用して、変換された結果を確認してください。
DeserializedType result = JsonConvert.DeserializeObject<DeserializedType>(json, new Converter(parms));
コンバーターをテストするには、コンバーターのリストに含まれている必要があります。 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);
カスタムコンバーターの内部動作を知らなくても、モックの代わりにテストダブルを作成できますか?
public class JsonReaderThatReturnsNull : JsonReader
{
public override bool Read()
{
return true;
}
public override object Value => null;
}