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

我可以逐步调试并验证返回的对象是否与我预期的测试对象匹配,但是当我调用Assert.Equivality(Expect,Result,True)时,xUnit抛出一个System.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);
}

Query窗口小部件类

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

QueryCount窗口小部件类

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填充在测试fixture 中;异常在Assert.Envalence调用结束时失败)

[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.Equivalence,而不会出现问题.我还将Widget类更改为测试:

  1. 已使用QueryCountWidget将Widget.Data更改为虚拟,而不是抽象.Data仍在覆盖:相同异常
  2. 使用QueryCountWidget.Data将Widget.Data更改为虚拟,而不是抽象:相同的异常
  3. 删除了Widget.Data属性,并让QueryCountWidget.Data仅作为Get Only属性返回:测试成功完成
  4. 已将Widget.Data更改为具有QueryCountWidget.Data类型的QueryCountWidget.Data仍在覆盖:测试成功完成

不幸的是,只有两个似乎有效的更改阻止了我以我想要的方式使用这些类. 我还有十几种其他类型的小部件,每种都有自己的关联WidgetData派生类型. 我真的不想单独测试每个属性,因为如果新属性被添加到Widget类中,那就不能考虑future 的开发. 有没有什么方法可以让它与xUnit一起工作,而不 destruct 我的类 struct ?

推荐答案

您对xUnit中的Assert.Equivalent的问题似乎源于xUnit的断言机制如何处理继承类中的属性的冲突,特别是在处理被覆盖的属性时.

在xUnit中,Assert.Equivalent用于比较两个对象的 struct 是否相等,这意味着它判断它们是否具有相同的数据,而不一定是相同的实例.但是,当它遇到重写的属性时,特别是在具有协变返回类型的场景中,它可能无法正确处理比较,从而导致您遇到的异常.

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

Assert.Equivalent(expected, result, true);

有:

result.Should().BeEquivalentTo(expected);

这就像预期的那样工作,没有抛出任何错误,在我看来可读性更好.

Csharp相关问答推荐

为什么我在PuppeteerSharp中运行StealthPlugin时会出现错误?

EF Core:看不到任何查询日志(log)?

react 式扩展连接中的非交叉LeftDurationTimeout

在一个模拟上设置一个方法,该模拟具有一个参数,该参数是一个numc函数表达式

在实时数据库中匹配两个玩家的问题

有没有办法在WPF文本框中添加复制事件的处理程序?

如何使用新的Microsoft.IdentityModel.JsonWebToken创建JwtSecurityToken?

Docker Container中的HttpRequest后地址不可用

在C#中,非静态接口方法的抽象和虚拟是冗余的吗?

带有可选参数的模拟方法返回意外的不同值,具体取决于可选的默认值

同一组件的多个实例触发相同的事件处理程序

为什么我的伺服电机不动,下面的代码?

MSI无法将快捷方式添加到启动文件夹

在.NET Maui中,Flyoutindow/Hamburger菜单可以在shell 之外实现吗?

如何在C#.NET桌面应用程序中动态更改焦点工具上的后退 colored颜色

读取测试项目中的应用程序设置

与另一个对象位于同一位置的对象具有不同的变换位置

我如何为我的Blazor应用程序构建一个动态教程标注?

MS Project读取项目自定义域

阻止CLR释放已封送的双字符指针的内存?