FluentAssertions - Сравнение объектов, содержащих свойства с похожими именами, но разных типов - PullRequest
1 голос
/ 19 сентября 2019

У меня есть несколько классов в нашем коде, которые автоматически генерируются инструментом генератора XSD из определений файла XSD.Классы очень похожи с похожими именами, но на основе схемы XSD (которую мы получили от внешнего поставщика) все сгенерированные классы имеют разные типы.И это довольно сложные классы с множеством глубоких вложенных свойств и перечислимых значений.Следовательно, мы привыкли работать с классами напрямую, потому что было сложно использовать обобщенный подход для работы с классами.

Но я принял вызов, и мне (вроде) это удалось.Чтобы избежать дублирования кода при работе с этими классами, я добавил свойства в классы, используя определения интерфейса вне файла, сгенерированного XSD, чтобы предотвратить их перезапись при повторной генерации классов, используя преимущества частичного объявления класса, например:

Упрощенный пример сгенерированных классов XSD

public partial class xsdGeneratedClass1
{
    public xsdGeneratedClass1Header header { get; set }
    public xsdGeneratedClass1Body body { get; set; }
}

public partial class xsdGeneratedClass2
{
    public xsdGeneratedClass2Header header { get; set }
    public xsdGeneratedClass2Body body { get; set; }
}

Упрощенный пример интерфейса, где свойства также состоят из интерфейсов типов, которые мы написаличтобы сопоставить свойства в сгенерированных XSD классах

public interface IXsdGeneratedClass
{
    IXsdGeneratedClassHeader header { get; set; }
    IXsdGeneratedClassBody body { get; set; }
}

Упрощенный пример реализации интерфейса вне файла, сгенерированного XSD

public partial class xsdGeneratedClass1 : IXsdGeneratedClass
{
    public IXsdGeneratedClassHeader header { get; set; }
    public IXsdGeneratedClassBody body { get; set; }
}

public partial class xsdGeneratedClass2 : IXsdGeneratedClass
{
    public IXsdGeneratedClassHeader header { get; set; }
    public IXsdGeneratedClassBody body { get; set; }
}

В этом упрощенном примере эта конструкция позволяет мне работать со свойствами заголовка и тела, используя интерфейсы вместо конкретных реализаций, для десятков классов, которые мы имеем с одинаковой структурой, но с разными типами классов, без редактирования в автоматически сгенерированном кодеиз XSD орудие труда.Это все работает отлично и прекрасно.

Проблема возникает при попытке сравнить объекты в наших модульных тестах, используя Fluent Assertions.Кажется, что у Fluent Assertions есть проблема, зная, какие свойства экземпляров объектов сравнивать.В этом простом примере экземпляр объекта xsdGeneratedClass1 будет иметь четыре свойства:

  1. public xsdGeneratedClass1Header header {get;set}
  2. public xsdGeneratedClass1Body body {get;установлен;}
  3. public IXsdGeneratedClassHeader header {get;установлен;}
  4. public IXsdGeneratedClassBody body {get;установлен;}

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

class1.Should().BeEquivalentTo(expectedClass);

Но кажется, что Fluent Assertions постоянно сравнивает заголовок IXsdGeneratedClassHeader класса 1 с заголовком Ожидаемый класс xsdGeneratedClass1Header, который равен нулю.

Я пытался использоватьопция RespectingRuntimeTypes, которая выполняет тест, но кажется, что он не сравнивает объекты должным образом.Если я изменю значение свойства в свойстве заголовка Ожидаемого класса, например, которое, как я знаю, не будет совпадать со значением в классе 1, тест все равно пройдет.

Я попытался отыскать ответы в Интернете, и я 'Я заканчиваю свои поиски и в основном размышляю над тем, должен ли я просто написать свой собственный инструмент или сделать несколько ручных утверждений.Оби-Ван Утверждения, пожалуйста, помогите!

1 Ответ

0 голосов
/ 27 сентября 2019

Большое спасибо, Джонас Нируп!Кажется, это дефект, который сейчас исправлен в основной ветке Fluent Assertions.Тем временем кто-то опубликовал ответ в ветке github для обходного пути, который также работал для меня.Очень счастлив.Спасибо!

Объявите этот класс где-нибудь, доступным для использования в ваших модульных тестах

public class ReflectionMemberMatchingRule : IMemberMatchingRule
{
    public SelectedMemberInfo Match(SelectedMemberInfo expectedMember, object subject, string memberPath, IEquivalencyAssertionOptions config) => expectedMember;
}

Используйте класс расширения в своих модульных тестах, добавив конфигурацию в Fluent Assertions.

AssertionOptions.AssertEquivalencyUsing(x => x.Using(new ReflectionMemberMatchingRule()));

Теперь работает как положено!

...