Как управлять «Равенством» для членов словаря, используя FluentAssertions - PullRequest
0 голосов
/ 24 июня 2018

Есть ли способ, с помощью FluentAssertions, контролировать, как значения словаря сравниваются на равенство?

У меня есть класс, одним свойством которого является словарь (string / double).Я хотел бы сравнить два экземпляра класса (ожидаемый и фактический) и для членов словаря, чтобы указать, как определяется «равенство».

Предполагая, что у меня есть класс, как показано:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var t1 = new Thing();
        t1.Name = "Bob";
        t1.Values.Add("Hello", 100.111);
        t1.Values.Add("There", 100.112);
        t1.Values.Add("World", 100.113);

        var t2 = new Thing();
        t2.Name = "Bob";
        t2.Values.Add("Hello", 100.111);
        t2.Values.Add("There", 100.112);
        t2.Values.Add("World", 100.1133);

        t1.Should().BeEquivalentTo(t2);
    }
}

public class Thing
{
    public string Name { get; set; }

    public Dictionary<string, double> Values { get; set; } = new Dictionary<string, double>();
}

Я бы хотел указать, как, например, сравнивается запись «Мир» в словаре.В действительности это может быть то, что значения могут быть очень большими или одинаковыми для десятичных знаков (но не после), но я думаю, что мне может понадобиться сказать что-то вроде «то же самое, если разница менее 1%).

Мне нравится, как FluentAssertions сообщает мне об этом члене и почему они не совпадают, и попробовал пользовательский IAssertionRule (используя Options lambda), но он только сравнивал свойства класса, а не членов словаря.

Мне не принадлежат сравниваемые классы, поэтому я не могу переопределить метод "Equal", и я не могу найти способ указать пользовательский компаратор (IEquatable) - но я подозреваю, что потерял бы беглые детали того, почемуони не одинаковы.

Если бы это было возможно, но то, что любой метод также применялся бы к двойникам, которые были свойствами класса (в отличие от значений в словаре), это было бы нормально.

Спасибо.

Ответы [ 3 ]

0 голосов
/ 25 июня 2018

Исходя из ответа Nkosi, это пример BeAppximately, который я использую (чтобы разрешить использование BeApproximately с decimal?):

    [CustomAssertion]
    public static void BeApproximately(this NullableNumericAssertions<decimal> value, decimal? expected, decimal precision, string because = "",
        params object[] becauseArgs)
    {
        if (expected == null)
            value.BeNull(because);
        else
        {
            if (!Execute.Assertion.ForCondition(value.Subject != null).BecauseOf(because)
                .FailWith($"Expected {{context:subject}} to be '{expected}' {{reason}} but found null"))
                return;

            Decimal num = Math.Abs(expected.Value - (Decimal) value.Subject);

            Execute.Assertion.ForCondition(num <= precision).BecauseOf(because, becauseArgs).FailWith("Expected {context:value} to approximate {1} +/- {2}{reason}, but {0} differed by {3}.", (object) value.Subject, (object) expected.Value, (object) precision, (object) num);
        }
    }
0 голосов
/ 25 июня 2018

Исходя из превосходного поста Михала, я начал работать со следующим, что показывает отличное обещание:

    [CustomAssertion]
    public static void BeWithinPercentageOf(this NumericAssertions<double> value, double expected, double tolerance, string because = "", params object[] becauseArgs)
    {
        if (!Execute.Assertion.ForCondition(value.Subject != null)
            .BecauseOf(because)
            .FailWith($"Expected {{context:subject}} to be '{expected}' {{reason}} but found null"))
            return;

        var actual = (double)value.Subject;
        var diff = Math.Abs(expected - actual);

        if (diff > double.Epsilon)
        {
            var percent = Math.Round(100 / (expected / diff), 2);

            Execute.Assertion.ForCondition(percent <= tolerance)
                .BecauseOf(because, becauseArgs)
                .FailWith("Expected {context:value} to be {1} (±{2}%){reason}, but {0} differed by {3}%.", actual, expected, tolerance, percent);
        }
    }
0 голосов
/ 24 июня 2018

BeApproximately может использоваться для сравнения двойников в допустимом диапазоне точности.Использование этого вместе с настройкой точности для всех двойных чисел должно удовлетворять желаемому поведению.

t1.Should().BeEquivalentTo(t2, options => options
    .Using<double>(ctx => 
        ctx.Subject.Should().BeApproximately(ctx.Expectation, ctx.Expectation * 0.01D))
    .WhenTypeIs<double>()
);

Ссылка Сравнение графов объектов: поведение сравнения эквивалентности

...