我试图通过添加一些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'
有谁知道这是可能的还是我出错的地方?
您需要将此参数作为参数传递给扩展方法的对象实例。在你的情况下,这将是正确的语法
var assert = new Assert();
assert.ElementPresent(...);
但我想你不需要甚至不能创建Assert类的实例。
你要做的是将扩展方法作为扩展类的静态调用来调用,并且不起作用。但为什么不简单地打电话
AssertExtensions.ElementPresent(...);
编辑2 xUnit 2最终最终将断言移动到一个单独的程序集中。在NuGet上有这个包的编译包和源包,并且Assert
类是部分的,因此通过使用包的源仅版本,Assert
变得非常容易扩展(在C#中,即)。
编辑为了更加完整:xUnit 2删除了此扩展点,并建议使用“fluent”断言库中的扩展方法。
为了完整起见,这里描述了扩展Assert
的“官方”方式(令人惊讶的是,尽管事实上Brad Wilson甚至加入了讨论,但仍然没有提及)。
从版本1.5(根据Brad的博客),xUnit.Extensions通过Assertions
和TestClass
类明确支持。它的工作原理如下:
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.net的Assert
是static
因此不能添加扩展(虽然其他Assertion库不起诉这种方法,这就是为什么人们可能期望使用扩展方法来扩展Assert
)。因此,在xUnit.net Universe中,如果要添加自定义断言,请添加具有不同名称的新静态类。
您可以通过以下方式更改课程来使您的方法发挥作用:
public static class AssertExtensions
{
public static void ElementPresent(this Assert assert, ...)
至:
public class AssertExtensions : XUnit.Assert
{
public static void ElementPresent(...)
然后使用@ BradWilson的添加技巧:
using Assert = MyProject.Web.Specs.PageLibrary.Extensions.AssertExtensions;
在任何需要扩展名的文件的顶部。
这种技术可以方便地添加重载来考虑它....
(明显的弱点是你不能通过Assert.
直接访问多个)
xUnit 2的解决方案摘要(为NuGet的2.1.0版本工作。)
断言是一个可以通过添加另一个部分来扩展的部分类。为此,您需要从源代码编译Assert程序集。您可以使用xunit.assert.source
NuGet获取源代码。
步骤
xunit.assert
NuGet包的引用。xunit.assert.source
包。Xunit
命名空间中,定义public partial class Assert
并在那里添加自定义断言。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 2+:
1)将xunit.assert.source
Nuget包添加到带扩展名的项目中。
2)创建部分类定义:
namespace xUnit
{
public partial class Assert
{
public static void 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's回答如何设置项目。