xUnit Assert.Equivalent 在尝试使用协变返回类型测试抽象属性时抛出 System.ArgumentException

问题描述 投票:0回答:1

我正在使用 xUnit 2.6.3(最新稳定版本)来测试 .Net 8 项目。我有一个继承自抽象类的对象,并且我正在测试的方法具有基类的返回类型。基类有一个名为 Data 的 WidgetData 类型抽象属性,该属性仅具有 getter,派生类通过返回 QueryCountWidgetData 类型(继承自 WidgetData)的对象来重写该属性。没有二传手。

我可以单步调试并验证返回的对象是否与我预期的测试对象匹配,但是当我调用 Assert.Equivalent(expected, result, true) 时,xUnit 会抛出 System.ArgumentException 并显示以下消息:具有相同键的项目有已经添加了。关键:数据。它是从 AssertHelper.GetGettersForType(Type 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.Equivalent 调用处失败)

[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.Equivalent ,不会出现问题。我还更改了 Widget 类来测试:

  1. 将 Widget.Data 更改为虚拟而不是抽象,并且 QueryCountWidget.Data 仍然覆盖:相同的异常
  2. 将 Widget.Data 更改为虚拟而不是抽象,并将 QueryCountWidget.Data 作为新的:相同的异常
  3. 删除了 Widget.Data 属性并让 QueryCountWidget.Data 仅作为仅获取属性返回:测试成功完成
  4. 将 Widget.Data 更改为 QueryCountWidgetData 类型,并且 QueryCountWidget.Data 仍然覆盖:测试成功完成

不幸的是,仅有的两个似乎有效的更改阻止了我按照我想要的方式使用这些类。我有十几种其他类型的小部件,每种都有自己关联的 WidgetData 派生类型。我真的不想单独测试每个属性,因为如果将新属性添加到 Widget 类中,这并不能说明未来的开发。有没有办法让它与 xUnit 一起工作而不破坏我的类结构?

c# .net xunit covariance
1个回答
0
投票

您对

xUnit
中的 Assert.Equivalent 的问题似乎源于 xUnit 的断言机制处理继承类中的属性的方式发生冲突,特别是在处理重写的属性时。

在 xUnit 中,

Assert.Equivalent
旨在比较两个对象的结构相等性,这意味着它检查它们是否具有相同的数据,而不一定是相同的实例。但是,当它遇到重写的属性时,尤其是在像您这样具有协变返回类型的场景中,它可能无法正确处理比较,从而导致像您遇到的那样的异常。

我建议你使用流行的NuGet包

FluentAssertions
并替换这行代码:

Assert.Equivalent(expected, result, true);

与:

result.Should().BeEquivalentTo(expected);

这按预期工作,不会引发任何错误,并且在我看来更具可读性。

© www.soinside.com 2019 - 2024. All rights reserved.