代码之家  ›  专栏  ›  技术社区  ›  jvance

xUnit断言。等效投掷系统。尝试测试具有协变返回类型的抽象属性时出现ArgumentException

  •  1
  • jvance  · 技术社区  · 1 年前

    我正在使用xUnit2.6.3(最新的稳定版)来测试。Net 8项目。我有一个从抽象类继承的对象,我正在测试的方法有一个基类的返回类型。基类有一个名为Data的抽象属性,其类型为WidgetData,只有一个getter,派生类通过返回从WidgetData继承的QueryCountWidgetData类型的对象来覆盖该属性。没有二传手。

    我可以逐步调试并验证返回的对象是否与我期望的测试对象匹配,但当我调用Assert时。等价(预期,结果,true),xUnit抛出一个系统。ArgumentException,消息为:已添加具有相同键的项。关键:数据。它是从AssertHelper抛出的。GetGettersForType(Type类型)方法。我的对象定义和测试代码如下。我做错了什么吗?xUnit还没有容纳协变返回类型吗?还是这完全不同?

    小工具类

    public abstract class Widget
    {
        public virtual string Title { get; set; }
        public int RowSpan { get; set; }
        public int ColumnSpan { get; set; }
        public int Row { get; set; }
        public int Column { get; set; }
        public string BackgroundColor { get; set; } = "DarkGray";
        public int DefaultFontSize { get; set; }
        public abstract WidgetData Data { get; }
        public abstract void SetData(object data);
    }
    

    QueryWidget类

    public abstract class QueryWidget : Widget
    {
        public Guid QueryId { get; set; }
        public List<SelectableQueryParameter> Parameters { get; set; }
        public DateSearchContext SearchContext { get; set; }
    }
    

    QueryCountWidget类

    public class QueryCountWidget : QueryWidget
    {
        private QueryCountWidgetData _data;
        public override QueryCountWidgetData Data => _data;
    
        public override void SetData(object data)
        {
            if (data is QueryCountWidgetData widgetData)
            {
                _data = widgetData;
            }
        }
    }
    

    WidgetData和QueryCountWidgetData类

    public abstract class WidgetData
    { }
    
    public class QueryCountWidgetData : WidgetData
    {
        public int? Count { get; set; }
    }
    

    测试方法(_queryCountWidgetNode填充在测试夹具中;异常在末尾的Assert.Equatival调用中失败)

    [Fact]
    public void DeserializeQueryCountWidget()
    {
        var result = DashboardXmlDeserializer.GetWidgetFromXmlNode(_queryCountWidgetNode);
        Assert.NotNull(result);
        Assert.IsType<QueryCountWidget>(result);
        var expected = new QueryCountWidget
        {
            Title = "QueryCount with Param",
            BackgroundColor = "DarkGray",
            Row = 0,
            RowSpan = 1,
            Column = 8,
            ColumnSpan = 1,
            SearchContext = new DateSearchContext
            {
                Name = "",
                DateFieldId = "",
                DateSearchShortcut = "All"
            },
            Parameters = new List<SelectableQueryParameter>
            {
                new SelectableQueryParameter
                {
                    Name = "@TestParam",
                    Value = "Scrap",
                    DataTypeString = "System.String",
                    Hidden = false,
                }
            },
            QueryId = Guid.Parse("f545ad33-647c-4596-ad7d-0b0a113e7e98"),
        };
        Assert.Equivalent(expected, result, true);
    }
    

    我一开始使用的是xUnit的旧版本,但我已经将xUnit更新到2.6.3,将xUnit.runner.visualstudio更新到2.5.5;两者都是最新的稳定版本。我已经验证了我可以调用Assert。每个财产的等价物单独存在,没有问题。我还更改了Widget类以进行测试:

    1. 更改的小工具。使用QueryCountWidget将数据转换为虚拟数据,而不是抽象数据。数据仍在覆盖:相同的异常
    2. 更改的小工具。使用QueryCountWidget将数据转换为虚拟数据,而不是抽象数据。数据为新数据:相同的异常
    3. 已删除小工具。Data属性,并让QueryCountWidget。数据仅作为get-only属性返回:测试成功完成
    4. 更改的小工具。数据的类型为QueryCountWidgetData和QueryCountWidget。数据仍覆盖:测试成功完成

    不幸的是,只有两个似乎有效的更改使我无法按自己的意愿使用这些类。我有十几种其他类型的小部件,每种都有自己关联的WidgetData派生类型。我真的不想单独测试每个属性,因为如果在Widget类中添加了新的属性,这就不能考虑未来的开发。有没有办法在不破坏我的类结构的情况下将其用于xUnit?

    1 回复  |  直到 1 年前
        1
  •  1
  •   Raul    1 年前

    您的问题 Assert.Equivalent 在里面 单元测试 似乎源于xUnit的断言机制如何处理继承类中的属性的冲突,尤其是在处理重写的属性时。

    在xUnit中, 明确肯定相等的 设计用于比较两个对象的结构相等性,这意味着它检查它们是否具有相同的数据,而不一定是同一个实例。然而,当它遇到被重写的属性时,特别是在像您这样具有协变返回类型的场景中,它可能无法正确处理比较,从而导致像您遇到的异常。

    我建议你使用流行的NuGet包 FluentAssertions 并替换这行代码:

    Assert.Equivalent(expected, result, true);
    

    与:

    result.Should().BeEquivalentTo(expected);
    

    这正如预期的那样工作,没有任何错误,在我看来可读性更强。

    推荐文章