用新的断言扩展XUnit Assert类



我试图通过添加一些selenium功能来扩展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'

有没有人知道这是可能的,或者我哪里错了?

Edit 2 xUnit 2最终将断言完全移动到一个单独的程序集中。NuGet上有编译过的和只有源代码的包,Assert类是部分的,所以通过使用只有源代码的包,Assert变得非常容易扩展(在c#中,也就是说)。

Edit为了更完整:xUnit 2删除了这个扩展点,并建议使用'fluent'断言库的扩展方法。


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

从版本1.5(根据Brad的博客),xUnit。扩展通过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.
    }
}

现在您需要从Xunit.Extensions.TestClass派生您的测试类(令人困惑的是,还有Xunit.TestClass,这不是您想要的),并且如果您没有明确限定名称,Assert属性将"遮蔽"Xunit.Assert类型。

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

Assert.DeepEquals(expectedXml, actualXml);

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

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

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

  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]}");
            }
        }
    }
}

注:其他答案和编辑也指出了解决方案,但我花了相当长的时间才从那里弄清楚。此外,我并不是说这是唯一或最好的选择。

对不起,你弄糊涂了(编辑:我也是!)xUnit.net的Assertstatic,因此不能添加扩展(尽管其他断言库不使用这种方法,这就是为什么人们可能期望使用扩展方法来扩展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; 

放在需要扩展名的文件的顶部。

这个技术对于添加重载很方便,想想看....

(明显的缺点是不能通过Assert.直接访问多个对象)

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

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

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

你要做的是调用扩展方法作为静态调用扩展类,这是行不通的。但是为什么不直接调用

呢?
 AssertExtensions.ElementPresent(...);

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

因为Assert类的构造函数设置为protected,所以你不能为它创建Extension Method,因为你不能实例化它。

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

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

和使用:

MyExtendedAssert.ElementPresent(...);

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

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

阅读Premil的答案如何设置项目

我能够得到@Premil发布的解决方案,但我不得不参考xunit.core而不是xunit.extensibility.execution

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

对于xUnit 2+:

  1. 添加xunit.assert.source Nuget包到带有扩展的项目。

  2. 创建部分类定义:

namespace Xunit
{
  public partial class Assert
  {
    public static void ElementPresent(...)
    {
    }
  }
}

您可以创建Xunit.Assert的子类,并在子类中添加额外的静态方法。

我调用我的子类Assert,所以我不需要重命名任何现有的断言,所以我不需要记住我的子类的名字是什么。

public class Assert : Xunit.Assert
{
    public static void DoesXyz()
    {
        // test for XYZ
        Assert.True(true);
    }
}

然后在你的测试中:

public class Tests
{
    [Fact]
    public void CanUseDoesXyz()
    {
        Assert.DoesXyz();
    }
}

相关内容

  • 没有找到相关文章

最新更新