使用FluentAssertions比较包含不同类型的两个字典集合

时间:2018-04-16 06:11:06

标签: c# unit-testing fluent-assertions

在我们的数据库中,我们查询放置在字段上实现ExpandoObject的{​​{1}}类型的动态对象集合中的记录集。这些是实际值。

从我们的SpecFlow BDD测试中,我们得到了一个实现IDictionary<string, object>的TableRows集合。这些是我们的预期值。

使用FluentAssertions,我们希望使用IDictionary<string, string>测试整个集合的等效性。遗憾的是,由于实际值不属于actual.Should().BeEquivalentTo(expected)类型时类型不匹配,因此无法正常工作。

我们可以使用string,但这会使整个实际集合成为actual.Should().BeEquivalentTo(expected, options => options.WithAutoConversion())的集合,这对于比较日期无用。

我组装了一个将显示相同问题的测试用例:

IDictionary<string, string>

我尝试使用以下方法使接收类型动态化:

var expected = new List<Dictionary<string, string>>();
expected.Add(new Dictionary<string, string>
{
    {"Name", "Moon Inc."},
    {"Number", "42"},
    {"Date", "2018-12-31"}
});

var actual = new List<ExpandoObject>();
dynamic eo = new ExpandoObject();
eo.Name = "Moon Inc.";
eo.Number = 42;
eo.Date = new DateTime(2018, 12, 31);

actual.Add(eo);

actual.Should().BeEquivalentTo(expected, options => options);
/* 
    This throws:
    NUnit.Framework.AssertionException: 
    Expected item[0][Number] to be System.String, but found System.Int32.
    Expected item[0][Date] to be System.String, but found System.DateTime.
*/

actual.Should().BeEquivalentTo(expected, options => options.WithAutoConversion());
/*
    This throws:
    NUnit.Framework.AssertionException: 
    Expected item[0][Date] to be "2018-12-31" with a length of 10, 
    but "31-12-2018 0:00:00" has a length of 18.
/*

将双方解析为actual.Should().BeEquivalentTo(expected, options => options .Using<dynamic>(ctx => ctx.Subject.Should().Be(ctx.Expectation)).WhenTypeIs<DateTime>() .Using<dynamic>(ctx => ctx.Subject.Should().Be(ctx.Expectation)).WhenTypeIs<int>()); /* NUnit.Framework.AssertionException: Expected item[0][Number] to be System.String, but found System.Int32. Expected item[0][Date] to be System.String, but found System.DateTime. */ 并使用自动转换也不起作用,因为DateTime类型不被视为actual而是DateTime

string

有没有办法用FluentAssertions实现这一目标?

1 个答案:

答案 0 :(得分:2)

如果没有其他帮助,您可以像这样实现自定义IEquivalencyStep

class WeakDateEquivalencyStep : IEquivalencyStep {
    public bool CanHandle(IEquivalencyValidationContext context, IEquivalencyAssertionOptions config) {
        if (context.IsRoot)
            return false;
        // handles situations when subject is date
        // but expectation is string
        return context.Subject is DateTime && context.Expectation is string;
    }

    public bool Handle(IEquivalencyValidationContext context, IEquivalencyValidator parent, IEquivalencyAssertionOptions config) {
        DateTime exp;
        // we know that expection is string here
        if (!DateTime.TryParse((string) context.Expectation, CultureInfo.InvariantCulture, DateTimeStyles.None, out exp)) {
            // do something, your spec is invalid
            throw new Exception($"Value {context.Expectation} does not represent valid date time");
        }

        context.Subject.Should().Be(exp, context.Because, context.BecauseArgs);
        return true;
    }
}

然后

actual.Should().BeEquivalentTo(expected, options => 
   options.Using(new WeakDateEquivalencyStep()).WithAutoConversion());