14

我正在尝试通过添加一些硒功能来扩展 xUnit 断言方法

namespace MyProject.Web.Specs.PageLibrary.Extensions
{
    public static class AssertExtensions
    {
        public static void ElementPresent(this Assert assert, ...)
        {
            if (...)
            {
                throw new AssertException(...);
            }
        }
    }
}

但是当我尝试使用它时出现这个编译错误。

using MyProject.Web.Specs.PageLibrary.Extensions;    
using Xunit;
...

public void DoSomething()
{
    Assert.ElementPresent(...);
}

和错误

Error   5   'Xunit.Assert' does not contain a definition for 'ElementPresent'

有谁知道这是否可能或我哪里出错了?

4

8 回答 8

14

Edit 2 xUnit 2 最终将断言完全移到了一个单独的程序集中。在 NuGet 上既有编译包也有源包,并且Assert类是部分的,因此通过使用包的仅限源版本,Assert变得非常容易扩展(即在 C# 中)。

编辑为了更完整:xUnit 2 删除了这个扩展点,并建议使用“流利的”断言库的扩展方法。


为了完整起见,这里是对“官方”扩展方式的描述Assert(令人惊讶的是,它根本没有被提及,尽管 Brad Wilson 甚至加入了讨论)。

从版本 1.5(根据 Brad 的博客)开始,xUnit.Extensions 通过AssertionsTestClass类明确支持这一点。它是这样工作的:

TestClass有一个名为Assertthat 的属性,它是Assertions中继所有方法的类型Xunit.Assert。因为TestClass.Assert是一个实例,你可以通过扩展方法给它添加方法Assertions

public static class AssertionsExtensions
{
    public static void DeepEquals(this Assertions assertions, XNode expected, XNode actual)
    {
        assertions.True(XNode.DeepEquals(expected, actual)); // You can also use Assert.True here, there's effectively no difference.
    }
}

现在您需要让您的测试类派生自Xunit.Extensions.TestClass(令人困惑的是,还有Xunit.TestClass,这不是您想要的),如果您没有明确限定名称,该Assert属性将“隐藏”类型。Xunit.Assert

在派生自 的测试类中TestClass,您现在可以使用

Assert.DeepEquals(expectedXml, actualXml);

与内置 xUnit 断言的唯一真正区别(除了语法着色Assert是标识符,而不是类型的事实)是,当它失败时,您只需得到 a TrueException,而不是DeepEqualsException可以假设告诉您在哪里的具体比较失败。当然,你也可以用同样的方式来构建它。

于 2014-05-04T02:25:34.127 回答
11

xUnit 2的解决方案摘要。(为 NuGet 的 2.1.0 版为我工作。)

Assert 是一个部分类,您可以通过添加另一个部分来扩展它。为此,您需要从源代码编译 Assert 程序集。您可以使用xunit.assert.sourceNuGet 获取源代码。

步骤

  1. 从项目中删除xunit.assertNuGet 包的引用。
  2. 而是安装xunit.assert.source包。
  3. Xunit命名空间中,定义public partial class Assert并添加您的自定义断言。
  4. 在您的测试项目中安装xunit.extensibility.execution包(否则两个不同的Assert类之间会发生冲突并且测试将不会运行,因为xunit.execution.*.dll会丢失)

自定义断言示例:

namespace Xunit
{ 
    public partial class Assert
    {
        public static void ArraySegmentEqual<T>(
            T[] expectedSequence, T[] buffer, int offset = 0)
        {
            for (int i = 0; i < expectedSequence.Length; i++)
            {
                int b = i + offset;

                True(buffer[b].Equals(expectedSequence[i]),
                    $"Byte #{b} differs: {buffer[b]} != {expectedSequence[i]}");
            }
        }
    }
}

注意:其他答案和编辑也指向解决方案,但我花了很多时间才从那里弄清楚。此外,我并不声称这是唯一或最好的选择。

于 2016-03-18T15:32:41.630 回答
10

抱歉,但您感到困惑(编辑:我也是!)。xUnit.netAssert static,因此不能添加扩展(尽管其他断言库不起诉这种方法,这就是为什么人们可能期望使用扩展方法来扩展Assert)。因此,在 xUnit.net 世界中,如果要添加自定义断言,请添加一个具有不同名称的新静态类。

您可以通过以下方式更改您的课程来使您的方法有效:

public static class AssertExtensions
{
    public static void ElementPresent(this Assert assert, ...)

至:

public class AssertExtensions : XUnit.Assert
{
    public static void ElementPresent(...)

然后使用Brad Wilson的添加技巧:

using Assert = MyProject.Web.Specs.PageLibrary.Extensions.AssertExtensions; 

在任何需要您的扩展名的文件的顶部。

这种技术对于添加重载很方便。

(明显的弱点是你不能有多个直接访问 via Assert.

于 2013-04-24T23:56:41.237 回答
2

您需要将作为此参数传递给扩展方法的对象实例。在您的情况下,这将是正确的语法

var assert = new Assert();
assert.ElementPresent(...);

但我想你不需要甚至不能创建 Assert 类的实例。

您正在尝试做的是调用扩展方法作为扩展类的静态调用,这将不起作用。但为什么不简单地打电话

 AssertExtensions.ElementPresent(...);
于 2013-04-24T20:10:31.483 回答
0

我使用一个简单的partial助手来添加That属性,以便我可以轻松地在其他任何地方构建扩展:

// ReSharper disable once CheckNamespace
namespace Xunit
{
    public partial class Assert
    {
        [CanBeNull]
        public static Assert That => default;
    }
}

阅读Premil 的回答如何设置项目。

于 2019-05-21T14:21:36.163 回答
0

对于xUnit 2+

1)将xunit.assert.sourceNuget包添加到带有扩展名的项目中。

2)创建部分类定义:

namespace xUnit
{
  public partial class Assert
  {
    public static void ElementPresent(...)
    {
    }
  }
}
于 2018-02-02T15:31:21.513 回答
0

问题是由于一个简单的封装约束:

由于Assert该类已将构造函数设置为protected您无法Extension Method为它创建一个,因为您无法实例化它。

所以为了扩展Assert,你只需要继承它:

public class MyExtendedAssert : Assert
{
    public void ElementPresent(...)
    {
        ...
    }
}

并使用:

MyExtendedAssert.ElementPresent(...);
于 2019-04-07T07:06:58.270 回答
0

我能够让@Premil 发布的解决方案起作用,但我必须参考xunit.core而不是xunit.extensibility.execution.

示例 Visual Studio 2019 解决方案位于https://github.com/groberts314/TestXUnitCustomAssertions

于 2022-01-20T14:12:53.170 回答