使用新断言扩展XUnit Assert类

Nei*_*eil 8 c# extension-methods assert xunit.net

我试图通过添加一些selenium功能来扩展xUnit断言方法

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

但是当我尝试使用它时,我得到了这个编译错误.

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

public void DoSomething()
{
    Assert.ElementPresent(...);
}
Run Code Online (Sandbox Code Playgroud)

而错误

Error   5   'Xunit.Assert' does not contain a definition for 'ElementPresent'
Run Code Online (Sandbox Code Playgroud)

有谁知道这是可能的还是我出错的地方?

Tea*_*Dev 11

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

编辑为了更完整:xUnit 2删除了此扩展点,并建议使用"fluent"断言库中的扩展方法.


为了完整起见,这里是对"官方"扩展方式的描述Assert(尽管Brad Wilson甚至加入了讨论,但令人惊讶的是根本没有提到过).

从版本1.5(根据Brad的博客),xUnit.Extensions通过AssertionsTestClass类明确支持这一点.它的工作原理如下:

TestClass有一个名为属性的属性Assert,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.
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你需要让你的测试类派生出来Xunit.Extensions.TestClass(令人困惑的是,也有Xunit.TestClass,这不是你想要的),如果你没有明确限定名称,Assert属性将"遮蔽" Xunit.Assert类型.

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

Assert.DeepEquals(expectedXml, actualXml);
Run Code Online (Sandbox Code Playgroud)

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


Pre*_*mil 7

xUnit 2解决方案摘要。(为我提供了NuGet版本2.1.0的支持。)

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

步骤

  1. xunit.assert从项目中删除对NuGet包的引用。
  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]}");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:其他答案和编辑也指向解决方案,但是我花了不少时间才能从中弄清楚。另外,我不主张这是唯一或最佳选择。

  • 删除 xunit 包后,它将停止运行测试用例。需要添加 xunit.core 才能再次启动并运行测试用例。 (2认同)

Rub*_*ink 5

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

您可以通过以下方式更改课程来使您的方法发挥作用:

public static class AssertExtensions
{
    public static void ElementPresent(this Assert assert, ...)
Run Code Online (Sandbox Code Playgroud)

至:

public class AssertExtensions : XUnit.Assert
{
    public static void ElementPresent(...)
Run Code Online (Sandbox Code Playgroud)

然后使用@ BradWilson的添加技巧:

using Assert = MyProject.Web.Specs.PageLibrary.Extensions.AssertExtensions; 
Run Code Online (Sandbox Code Playgroud)

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

这种技术方便添加重载来考虑它....

(明显的弱点是你不能通过直接访问不止一个Assert.)

  • 我们有意识地让 Assert 不是一个静态类,以便它可以支持可扩展性。您可以向派生类添加新断言,然后始终使用新类,可能通过 using 指令,例如:`using Assert = MyNamespace.MyAssert;` (2认同)

jur*_*ure 2

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

var assert = new Assert();
assert.ElementPresent(...);
Run Code Online (Sandbox Code Playgroud)

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

您想要做的是将扩展方法作为扩展类的静态调用进行调用,但这是行不通的。但为什么不简单地打电话

 AssertExtensions.ElementPresent(...);
Run Code Online (Sandbox Code Playgroud)

  • 这不起作用,因为“Assert”的构造函数是“受保护的”。 (2认同)