FluentAssertions: проверьте, содержит ли Enumerable «подмножество» самого себя

Я ищу элегантное выражение, чтобы проверить, содержит ли перечислимое «подмножество» самого себя.

Позвольте мне проиллюстрировать на примере:

[Fact]
public void Test1()
{
    // Arrange
    var expected = new[]
    {
        new {F1 = 1, F2 = "1" },
        new {F1 = 2, F2 = "2" },
    };

    // Act
    var actual = new[]
    {
        new {F1 = 1, F2 = "1", F3 = true },
        new {F1 = 2, F2 = "2", F3 = true },
        new {F1 = 3, F2 = "3", F3 = true },
    };

    // Assert
    actual
        .Should()
        .LookingForFluentAssertionsExpression( //<-- I'm looking for this part
            expected, 
            options => options.SomeOptions(),
            because: "expected is a 'subset' of actual" 
        );
}

Я безуспешно пробовал Сравнение графов объектов:

    // Assert
    actual
        .Should()
        .BeEquivalentTo(expected, o => o.ExcludingMissingMembers());

Ожидается, что фактически будет коллекция с 2 элементами, но {{F1 = 1, F2 = 1, F3 = True}, {F1 = 2, F2 = 2, F3 = True}, {F1 = 3, F2 = 3, F3 = Истина }}"

"содержит на 1 элемент больше, чем"

{{F1 = 1, F2 = 1}, {F1 = 2, F2 = 2}}.

Очевидно, я могу сделать:

    // Assert
    actual
        .Where(a => expected.Any(e=>e.F1 == a.F1 && e.F2 == a.F2))
        .Should()
        .BeEquivalentTo(expected, o => o.ExcludingMissingMembers());

но выглядит немного грязно.

Другой вариант:

    // Assert
    expected
        .ToList()
        .ForEach(expectedItem =>
            actual
                .Should()
                .ContainEquivalentOf(
                    expectation: expectedItem, 
                    config: o => o.ExcludingMissingMembers())
        );

    // Or the same without Linq: 
    //
    //foreach (var expectedItem in expected)
    //{
    //    actual
    //        .Should()
    //        .ContainEquivalentOf(
    //            expectation: expectedItem,
    //            config: o => o.ExcludingMissingMembers());
    //}

но вообще не читается.

Вопрос немного вводит в заблуждение, вот какой был бы ответ, если бы вы действительно хотели протестировать подмножество: stackoverflow.com/questions/3274541/…. Ну, я вижу проблему с вашим кодом, вы используете анонимные объекты, которые, когда дело доходит до равенства, вы проверяете ссылку на объект. Я бы предложил использовать реальный объект и переопределить функцию Equals.

panoskarajohn 31.01.2023 10:02

Привет @panoskarajohn, спасибо за твой комментарий. Это всего лишь «минимально воспроизводимый образец». В моем сценарии переопределение Equals нецелесообразно. Помните, что у FluentAssertions есть методы для проверки графов объектов (<- я только что обновил свой вопрос, чтобы поговорить о сравнении графов объектов)

dani herrera 31.01.2023 10:22

Вставьте actual в HashSet<>. После этого вы можете вызвать actualHashSet.IsSupersetOf(expected). Имейте в виду, что в зависимости от типа вы должны указать IEqualityComparer<T> в ctor хеш-набора, но анонимные типы имеют семантику значений, поэтому в вашем примере это не нужно. Также вы можете сделать обратное и вызвать expectedHashSet.IsSubsetOf(actual), в зависимости от ваших потребностей.

Oliver 31.01.2023 10:30

@Oliver, большое спасибо за ваше предложение, можете ли вы уточнить его в ответе или в сути с небольшим количеством кода? Спасибо!

dani herrera 31.01.2023 10:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать два вызова ContainEquivalentOf, когда вы передаете элемент из коллекции expected.

например

using (new AssertionScope())
{
  actual.Should().ContainEquivalentOf(expected[0]);
  actual.Should().ContainEquivalentOf(expected[1]);
}

И не надо ExcludingMissingMembers. FA будет ожидать только те свойства, которые вы определили в соответствии с вашими ожиданиями.

Не могли бы вы уточнить немного кода, пожалуйста?

dani herrera 31.01.2023 10:32

Выглядит хорошо для нескольких предметов. Спасибо

dani herrera 31.01.2023 14:35

Что вы об этом думаете: stackoverflow.com/a/75296827/842935

dani herrera 31.01.2023 14:41

Выглядит слишком сложным для меня. Простая петля тоже сработала бы. Вы даже можете обернуть этот цикл в AssertionScope, как в моем примере.

Dennis Doomen 03.02.2023 09:03

В конце я закодировал его, используя ClassData. Я не знаю, лучшее ли это решение, я публикую его здесь с другими ответами. Не стесняйтесь критиковать этот ответ. Мы здесь, чтобы учиться.

public class CalculatorTestData : IEnumerable<object[]>
{
    public IEnumerator<object[]> GetEnumerator()
    {
        yield return new object[] { new { F1 = 1, F2 = "1" }, "reason 1" };
        yield return new object[] { new { F1 = 2, F2 = "2" }, "reason 2" };
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

[Theory]
[ClassData(typeof(CalculatorTestData))]
public void Test2(object expected, string because)
{
    // Arrange

    // Act
    var actual = new[]
    {
        new {F1 = 1, F2 = "1", F3 = true },
        new {F1 = 2, F2 = "2", F3 = true },
        new {F1 = 3, F2 = "3", F3 = true },
    };

    // Assert
    actual
        .Should()
        .ContainEquivalentOf(
            expectation: expected,
            because: because);
}

Другие вопросы по теме