Nano Hash - криптовалюты, майнинг, программирование

С# - утверждение, что два объекта равны в модульных тестах

Либо используя Nunit, либо Microsoft.VisualStudio.TestTools.UnitTesting. Прямо сейчас мое утверждение терпит неудачу.

    [TestMethod]
    public void GivenEmptyBoardExpectEmptyBoard()
    {
        var test = new Board();

        var input = new Board()
            {
                Rows = new List<Row>()
                    {
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                    }
            };

        var expected = new Board()
        {
            Rows = new List<Row>()
                    {
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                        new Row(){Cells = new List<int>(){0,0,0,0}},
                    }
        };

        var lifeOrchestration = new LifeOrchestration();

        var actual = lifeOrchestration.Evolve(input);

        Assert.AreEqual(expected, actual);
    }


Ответы:


1

У вас есть два разных экземпляра Board, поэтому ваш вызов Assert.AreEqual завершится ошибкой. Даже если все их содержимое кажется одинаковым, вы сравниваете ссылки, а не базовые значения.

Вы должны указать, что делает два экземпляра Board равными.

Вы можете сделать это в своем тесте:

Assert.AreEqual(expected.Rows.Count, actual.Rows.Count);
Assert.AreEqual(expected.Rows[0].Cells[0], actual.Rows[0].Cells[0]);

// Lots more tests of equality...

Или вы можете сделать это в своих классах: (обратите внимание, я написал это на лету - вы захотите это настроить)

public class Board
{
    public List<Row> Rows = new List<Row>();

    public override bool Equals(object obj)
    {
        var board = obj as Board;

        if (board == null)
            return false;

        if (board.Rows.Count != Rows.Count)
            return false;

        return !board.Rows.Where((t, i) => !t.Equals(Rows[i])).Any();
    }

    public override int GetHashCode()
    {
        // determine what's appropriate to return here - a unique board id may be appropriate if available
    }
}

public class Row
{
    public List<int> Cells = new List<int>(); 

    public override bool Equals(object obj)
    {
        var row = obj as Row;

        if (row == null)
            return false;

        if (row.Cells.Count != Cells.Count)
            return false;

        if (row.Cells.Except(Cells).Any())
            return false;

        return true;
    }

    public override int GetHashCode()
    {
        // determine what's appropriate to return here - a unique row id may be appropriate if available
    }
}
08.05.2014
  • Хотя я почти никогда не занимаюсь разработкой на C# и вижу, что этот подход работает, я использую Enumerable.SequenceEquals() вместо этого, что должно, по крайней мере, сделать часть боли в этом решении немного меньше. 17.08.2017
  • Я думаю, что стоит отметить некоторые недостатки этого подхода: он вставляет код модульного тестирования в ваш производственный код, он создает больше производственного кода, который сам должен быть модульно протестирован, этот код может изменить поведение другого производственного кода, и на самом деле это не так. уменьшите общий объем кода, который вам нужен. 22.10.2018

  • 2

    Раньше я переопределял getHasCode и equals, но мне это никогда не нравилось, так как я не хочу менять свой производственный код ради модульного тестирования. А еще это какая-то боль.

    Затем я переключился на отражение, чтобы сравнить объекты, которые были менее инвазивными... но это много работы (много угловых случаев).

    В итоге использую:

    http://www.nuget.org/packages/DeepEqual/ Отлично работает.

    Обновление, 6 лет спустя:

    Теперь я использую более общую библиотеку fluentassertions для .NET, она делает то же самое, что и выше, но с большим количеством функций и хорошим DSL, конкретной заменой будет: https://fluentassertions.com/objectgraphs/

    Кроме того, после нескольких лет опыта я все еще не рекомендую маршрут переопределения, я бы даже посчитал это плохой практикой. Если вы не будете осторожны, вы можете вызвать проблемы с производительностью при использовании некоторых коллекций, таких как словари. Кроме того, когда придет время, когда у вас будет реальный бизнес-кейс для перегрузки этих методов, у вас будут проблемы, потому что у вас уже будет этот тестовый код. Рабочий код и тестовый код должны быть разделены, тестовый код не должен полагаться на детали реализации или хаки для достижения своей цели, это усложняет его поддержку и понимание.

    08.05.2014
  • Да, вы можете сделать такое утверждение: actual.ShouldDeepEqual(expected); где фактический и ожидаемый — это два ваших объекта для сравнения. 10.03.2020

  • 3

    ExpectedObjects поможет вам сравнить равенство по значению свойства. Он поддерживает:

    1. простой объект: ожидаемый.ToExpectedObject().ShouldEqual(фактический);
    2. коллекция: ожидаемый.ToExpectedObject().ShouldEqual(фактический);
    3. составной объект: ожидаемый.ToExpectedObject().ShouldEqual(фактический);
    4. частичное сравнение: ожидаемому объекту нужен дизайн с анонимным типом и используйте ожидаемый.ToExpectedObject().ShouldMatch(фактический)

    Я люблю ExpectedObjects, потому что мне нужно только вызвать 2 API для подтверждения сравнения объектов:

    1. ДолженРавно()
    2. ShouldMatch() для частичного сравнения
    14.09.2015
  • Проблема в том, что если это не равно, и вы должны найти, что не так, в чем разница. С подчиненными отношениями или большим количеством свойств это может стоить много времени. Если бы у кого-то было решение этой проблемы, было бы здорово. 30.07.2021

  • 4

    Мне нужно решение, которое не требует добавления зависимости, работает с модульными тестами VS, сравнивает значения полей двух объектов и сообщает мне обо всех неравных полях. Это то, что я придумал. Обратите внимание, что его можно расширить и для работы со значениями свойств.

    В моем случае это хорошо работает для сравнения результатов некоторой логики синтаксического анализа файлов, чтобы убедиться, что две технически «разные» записи имеют поля с одинаковыми значениями.

        public class AssertHelper
        {
            public static void HasEqualFieldValues<T>(T expected, T actual)
            {
                var failures = new List<string>();
                var fields = typeof(T).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
                foreach(var field in fields)
                {
                    var v1 = field.GetValue(expected);
                    var v2 = field.GetValue(actual);
                    if (v1 == null && v2 == null) continue;
                    if(!v1.Equals(v2)) failures.Add(string.Format("{0}: Expected:<{1}> Actual:<{2}>", field.Name, v1, v2));
                }
                if (failures.Any())
                    Assert.Fail("AssertHelper.HasEqualFieldValues failed. " + Environment.NewLine+ string.Join(Environment.NewLine, failures));
            }
        }
    
        [TestClass]
        public class AssertHelperTests
        {
            [TestMethod]     
            [ExpectedException(typeof(AssertFailedException))]           
            public void ShouldFailForDifferentClasses()
            {            
                var actual = new NewPaymentEntry() { acct = "1" };
                var expected = new NewPaymentEntry() { acct = "2" };
                AssertHelper.HasEqualFieldValues(expected, actual);
            }
        }
    
    19.01.2016
  • Придирка: использование failures.Count > 0 вместо failures.Any() избавляет от зависимости от System.Collections. 12.05.2016
  • Для проверки свойств мне пришлось изменить typeof(T).GetFields( на typeof(T).GetProperties(. 25.09.2017
  • if(!v1.Equals(v2)) Проверьте v1 на нулевое значение, возможное исключение NullReferenceException. 06.12.2017
  • Это не работает для элементов ссылочных типов, которые равны по содержимому, но не являются одной и той же ссылкой. 29.08.2019

  • 5

    Для тривиальных объектов, таких как объекты домена, DTO или сущности, вы можете просто сериализовать оба экземпляра в строку и сравнить эту строку:

    var object1Json = JsonConvert.SerializeObject(object1);
    var object2Json = JsonConvert.SerializeObject(object2);
    
    Assert.AreEqual(object1Json, object2Json);
    

    Это, конечно, имеет различные предостережения, поэтому оцените, содержит ли JSON для ваших классов ожидаемые значения, которые следует сравнивать.

    Например, если ваш класс содержит неуправляемые ресурсы или иным образом не сериализуемые свойства, они не будут правильно сравниваться. Он также сериализует только общедоступные свойства по умолчанию.

    29.08.2019

    6

    Методы Assert полагаются на Equals и GetHashcode объекта. Вы можете реализовать это, но если это равенство объектов не требуется вне модульных тестов, я бы вместо этого рассмотрел возможность сравнения отдельных типов примитивов на объекте. Похоже, что объекты достаточно просты, и переопределение равенства на самом деле не гарантируется.

    08.05.2014

    7

    Поскольку ни один из них еще не упоминался по этому вопросу, есть несколько других хорошо принятых библиотек, которые могут помочь с этой проблемой:

    1. Свободные утверждения — см. сравнение графов объектов

      actual.Should().BeEquivalentTo(expected);

    2. Семантическое сравнение

      Likeness<MyModel, MyModel>(actual).ShouldEqual(expected);

    Я лично предпочитаю Fluent Assertions, так как обеспечивает большую гибкость с исключениями элементов и т. д., а также поддерживает сравнение вложенных объектов из коробки.

    Надеюсь это поможет!

    22.05.2020
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..