Как сравнить два объекта Json, используя C # - PullRequest
0 голосов
/ 04 октября 2018

У меня есть два объекта Json, которые нужно сравнить ниже.Я использую библиотеки Newtonsoft для анализа Json.

string InstanceExpected = jsonExpected;
string InstanceActual = jsonActual;
var InstanceObjExpected = JObject.Parse(InstanceExpected);
var InstanceObjActual = JObject.Parse(InstanceActual);

И я использую Fluent Assertions для сравнения.Но проблема в том, что Беглое утверждение не удается, только если количество / имена атрибутов не совпадают.Если значения JSON отличаются, он проходит.Я требую сбой, когда значения отличаются.

InstanceObjActual.Should().BeEquivalentTo(InstanceObjExpected);

Например, у меня есть фактический и ожидаемый JSON для сравнения, как показано ниже.И используя приведенный выше способ сравнения, сделайте их Pass, что неправильно.

{
  "Name": "20181004164456",
  "objectId": "4ea9b00b-d601-44af-a990-3034af18fdb1%>"  
}

{
  "Name": "AAAAAAAAAAAA",
  "objectId": "4ea9b00b-d601-44af-a990-3034af18fdb1%>"  
}

Ответы [ 5 ]

0 голосов
/ 17 мая 2019

Сделан нерекурсивный метод, который удаляет двойников - идея состоит в том, чтобы удалить одинаковые элементы из очень похожих JSON, чтобы в каждом объекте оставались только разные узлы:

public void RemoveTwins(ref BreadthFirst bf1, ref BreadthFirst bf2) {
    JsonNode traversal = bf1.Next();
    Boolean removed = false;
    do {
        if (!removed) {
            if (bf2.Current != null) while (bf1.Level == bf2.Level && bf2.Next() != null) ;
            if (bf2.Current != null) while (bf1.Level != bf2.Level && bf2.Next() != null) ;
            else bf2.Current = bf2.root;
        }
        else traversal = bf1.Next();
        if (bf2.Level < 0) bf2.Current = bf2.Root;
        do {
            removed = bf1.NextAs(bf1.src, bf2, bf2.src);
            if (removed && bf1.Orphan && bf2.Orphan) {
                JsonNode same = bf1.Current.Parent;
                traversal = bf1.RemoveCurrent();
                same = bf2.Current.Parent;
                bf2.RemoveCurrent();
                bf1.UpdateLevel();
                bf2.UpdateLevel();
                if (traversal == null
                || bf1.Root == null || bf2.Root == null
                || (bf1.Level == 0 && bf1.Current.NodeBelow == null)) {
                    traversal = null;
                    break;
                }
            } else
            if (!removed) {
                break; 
            } else removed = false;
        } while (removed);
        if (!removed) traversal = bf1.Next();
    } while (traversal != null);
}

Полный код + парсерна моем GitHub (профиль или ниже).
Старая версия CSV, которая также сортирует входные данные, упомянутые в моем вопросе здесь Как сравнить большие JSON? (новый нет, поэтому он может быть очень медленным, когда одинобъектов в обратном порядке - было бы легче отсортировать во время синтаксического анализа или по крайней мере сравнить обоих соседей близнецов в качестве первого шага поиска)

0 голосов
/ 04 октября 2018

Я немного больше покопался и смог выяснить, почему тестовый код OP работает не так, как ожидалось.Мне удалось это исправить, установив и использовав пакет FluentAssertions.Json .

Одна важная вещь:

Обязательно укажите using FluentAssertions.Json в противном случаевозможны ложные срабатывания.

Код теста:

using FluentAssertions;
using FluentAssertions.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;

[TestFixture]
public class JsonTests
{
    [Test]
    public void JsonObject_ShouldBeEqualAsExpected()
    {
        JToken expected = JToken.Parse(@"{ ""Name"": ""20181004164456"", ""objectId"": ""4ea9b00b-d601-44af-a990-3034af18fdb1%>"" }");
        JToken actual = JToken.Parse(@"{ ""Name"": ""AAAAAAAAAAAA"", ""objectId"": ""4ea9b00b-d601-44af-a990-3034af18fdb1%>"" }");

        actual.Should().BeEquivalentTo(expected);
    }
}

Запуск теста:

Unit test results

0 голосов
/ 04 октября 2018

Один из вариантов - десериализовать строки json в объекты C # и сравнить их.

Этот подход требует больше работы по сравнению с использованием JToken.DeepEquals (как предложено @JessedeWit), но имеет преимущество в том, что дает лучшие сообщения об ошибках, если ваши тесты не пройдены (см. Скриншот ниже).

Ваша строка json может быть смоделирована в следующий класс:

public class Entity
{
    [JsonProperty("Name")]
    public string Name { get; set; }

    [JsonProperty("objectId")]
    public string ObjectId { get; set; }
}

В вашем тесте десериализуйте строки json в объекты и сравните их:

[TestFixture]
public class JsonTests
{
    [Test]
    public void JsonString_ShouldBeEqualAsExpected()
    {
        string jsonExpected = @"{ ""Name"": ""20181004164456"", ""objectId"": ""4ea9b00b-d601-44af-a990-3034af18fdb1%>"" }";
        string jsonActual = @"{ ""Name"": ""AAAAAAAAAAAA"", ""objectId"": ""4ea9b00b-d601-44af-a990-3034af18fdb1%>"" }";

        Entity expectedObject = JsonConvert.DeserializeObject<Entity>(jsonExpected);
        Entity actualObject = JsonConvert.DeserializeObject<Entity>(jsonActual);

        actualObject.Should().BeEquivalentTo(expectedObject);
    }
}

PS: я использовал NUnit и FluentAssertionsв моем методе испытаний.Выполнение теста:

Unit test results

0 голосов
/ 04 октября 2018

Рассмотрите возможность использования метода JToken.DeepEquals(), предоставленного Newtonsoft.Это будет выглядеть примерно так, независимо от того, какую среду тестирования вы используете:

Console.WriteLine(JToken.DeepEquals(InstanceObjActual, InstanceObjExpected));
// false
0 голосов
/ 04 октября 2018

После десериализации объекта json в C # правильным способом является реализация интерфейса IComparable в десериализованном классе и сравнение двух объектов.

Итак:

using System;
using System.Collections.Generic;

class MyObj : IComparable<MyObj>
{
    public string Name { get; set; }
    public string ObjectID { get; set; }

    public int CompareTo(MyObj other)
    {
        if ((this.Name.CompareTo(other.Name) == 0) &&
            (this.ObjectID.CompareTo(other.ObjectID) == 0))
        {
            return 0;
        }
        return -1;
    }
}
...