Как использовать Исключение в FluentAssertions, чтобы исключить определенную пару KeyValue в Словаре

Я использую FluentAssertions с ShouldBeEquivalentTo сравнить два словаря типа Dictionary<string, string> но хотите исключить одну или несколько конкретных пар KeyValue (поскольку в этом случае они содержат метки времени). Как это сделать?

Я пробовал такие вещи, как: opt => opt.Excluding(x => x.Single(kv => kv.Key == "MySearchKey")) но это приводит к ошибкам вроде: Message: System.ArgumentException : Expression <Convert(x.Single(kv => (kv.Key == "MySearchKey")))> cannot be used to select a member.

Возможно ли то, что я хочу? Или я должен исключить только значение, а не пару (может быть, даже лучше, потому что проверка ключа будет проверена)? Спасибо!

1 ответ

Решение

Excluding() предназначен для исключения членов типа, не исключая члена коллекции, см. документацию для получения дополнительной информации.

Примечание: приведенный ниже код предназначен для текущей стабильной версии 4.19.4 Fluent Assertions.

Пример: вы хотите сравнить экземпляры Person а также PersonDTO, но Person содержит AnotherProperty который вы хотите исключить из сравнения объектов.

var person = new Person
{
    FirstName = "John",
    LastName = "McClane",
    AnotherProperty = 42
};

var personDTO = new PersonDTO
{
    FirstName = "John",
    LastName = "McClane"
};

Здесь вы бы использовали Exclude исключить член типа.

person.ShouldBeEquivalentTo(personDTO, options => options.Excluding(e => e.AnotherProperty));

В вашем конкретном случае я бы не использовал ShouldBeEquivalentTo, Рассмотрим эти два экземпляра словаря, в которых вы хотите опустить член коллекции, здесь член с Key == "unknown",

var actual = new Dictionary<string, int>
{
    ["one"] = 1,
    ["two"] = 2,
    ["three"] = 3,
    ["unknown"] = -1,
    ["fail"] = -2
};

var expected = new Dictionary<string, int>
{
    ["one"] = 1,
    ["two"] = 2,
    ["three"] = 3
};

Вы можете просто отфильтровать нежелательные пары ключ-значение:

IEnumerable<KeyValuePair<string, int>> filtered = actual.Where(e => e.Key != "unknown");

Теперь утверждение будет между двумя IEnumerable<KeyValuePair<string, int>>s

filtered.Should().Equal(expected);

который выдаст следующее сообщение об ошибке подтверждения:

FluentAssertions.Execution.AssertionFailedException: 'Expected collection to be equal to {[one, 1], [two, 2], [three, 3]}, but {[one, 1], [two, 2], [three, 3], [fail, -2]} contains 1 item(s) too many.'

В противном случае превратить отфильтрованное перечисление обратно в словарь:

Dictionary<string, int> filteredDict = actual.Where(e => e.Key != "unknown")
    .ToDictionary(e => e.Key, e => e.Value);

Теперь вы будете сравнивать Dictionary<string, int>Снова:

filteredDict.Should().Equal(expected);

который выдаст следующее сообщение об ошибке подтверждения:

FluentAssertions.Execution.AssertionFailedException: 'Expected dictionary to be equal to {[one, 1], [two, 2], [three, 3]}, but found additional keys {"fail"}.'

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

public static class DictionaryExtensions
{
    public static IDictionary<TKey, TValue> ExceptKeys<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TKey[] keys)
    {
        if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
        if (keys == null) throw new ArgumentNullException(nameof(keys));

        return dictionary.Where(e => !keys.Contains(e.Key)).ToDictionary(e => e.Key, e => e.Value);
    }

    public static IDictionary<TKey, TValue> ExceptValues<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TValue[] values)
    {
        if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
        if (values == null) throw new ArgumentNullException(nameof(values));

        return dictionary.Where(e => !values.Contains(e.Value)).ToDictionary(e => e.Key, e => e.Value);
    }
}

Теперь вы можете написать, на мой взгляд, более четкий и краткий тест:

actual.ExceptKeys("unknown").Should().Equal(expected);
Другие вопросы по тегам