C# xUnit.net:全局设置+;拆卸?
这个问题是关于单元测试框架的 我需要在执行任何测试之前运行一些代码,在所有测试完成之后也需要运行一些代码。我认为应该有某种属性或标记接口来指示全局初始化和终止代码,但找不到它们 或者,如果以编程方式调用xUnit,还可以使用以下代码实现所需的功能:C# xUnit.net:全局设置+;拆卸?,c#,.net,xunit.net,C#,.net,Xunit.net,这个问题是关于单元测试框架的 我需要在执行任何测试之前运行一些代码,在所有测试完成之后也需要运行一些代码。我认为应该有某种属性或标记接口来指示全局初始化和终止代码,但找不到它们 或者,如果以编程方式调用xUnit,还可以使用以下代码实现所需的功能: static void Main() { try { MyGlobalSetup(); RunAllTests(); // What goes into this method? }
static void Main()
{
try
{
MyGlobalSetup();
RunAllTests(); // What goes into this method?
}
finally
{
MyGlobalTeardown();
}
}
有谁能给我一个关于如何以声明方式或编程方式运行一些全局设置/拆卸代码的提示吗?据我所知,xUnit没有全局初始化/拆卸扩展点。然而,创建一个是很容易的。只需创建一个实现
IDisposable
的基本测试类,并在构造函数中进行初始化,在IDisposable.Dispose
方法中进行拆卸。这看起来像这样:
public abstract class TestsBase : IDisposable
{
protected TestsBase()
{
// Do "global" initialization here; Called before every test method.
}
public void Dispose()
{
// Do "global" teardown here; Called after every test method.
}
}
public class DummyTests : TestsBase
{
// Add test methods
}
[CollectionDefinition("TestEngine")]
public class TestEngineInitializer: IDisposable, ICollectionFixture<TestEngineInitializer>
{
public TestEngineInitializer()
{
MyOwnTestEngine.Init();
}
public void Dispose()
{
MyOwnTestEngine.Cleanup();
}
}
[Collection("TestEngine")]
public class MyTests
{
public MyTests(TestEngineInitializer initializer)
{
}
但是,每个调用都将执行基类设置和拆卸代码。这可能不是你想要的,因为它不是很有效。更优化的版本将使用IClassFixture
接口来确保全局初始化/拆卸功能只调用一次。对于此版本,您不会从测试类扩展基类,而是实现IClassFixture
接口,其中t
引用您的fixture类:
using Xunit;
public class TestsFixture : IDisposable
{
public TestsFixture ()
{
// Do "global" initialization here; Only called once.
}
public void Dispose()
{
// Do "global" teardown here; Only called once.
}
}
public class DummyTests : IClassFixture<TestsFixture>
{
public DummyTests(TestsFixture data)
{
}
}
使用Xunit;
公共类测试固件:IDisposable
{
公共测试混合()
{
//在这里进行“全局”初始化;只调用一次。
}
公共空间处置()
{
//在此处执行“全局”拆卸;仅调用一次。
}
}
公共类DummyTests:IClassFixture
{
公共DummyTests(TestsFixture数据)
{
}
}
这将导致TestsFixture
的构造函数只运行一次
对于每一个被测试的类。因此,这取决于您想要在这两种方法中选择什么。有一个简单的解决方案。使用Fody.ModuleInit插件 它是一个nuget软件包,安装时会向项目中添加一个名为
ModuleInitializer.cs
的新文件。这里有一个静态方法,它在构建之后编织到程序集中,并在加载程序集之后和运行任何操作之前运行
我用它来解锁我购买的库的软件许可证。我总是忘记在每次测试中解锁许可证,甚至忘记从一个可以解锁许可证的基类派生测试。编写这个库的明亮火花并没有告诉您它是许可证锁定的,而是引入了微妙的数字错误,导致测试在不应该的时候失败或通过。您永远不会知道是否已正确解锁库。现在我的模块init看起来像
/// <summary>
/// Used by the ModuleInit. All code inside the Initialize method is ran as soon as the assembly is loaded.
/// </summary>
public static class ModuleInitializer
{
/// <summary>
/// Initializes the module.
/// </summary>
public static void Initialize()
{
SomeLibrary.LicenceUtility.Unlock("XXXX-XXXX-XXXX-XXXX-XXXX");
}
}
//
///由模块单元使用。一旦加载程序集,Initialize方法中的所有代码都将立即运行。
///
公共静态类模块初始化器
{
///
///初始化模块。
///
公共静态void Initialize()
{
SomeLibrary.LicenseUtility.Unlock(“XXXX-XXXX-XXXX-XXXX-XXXX”);
}
}
并且放置在此程序集中的所有测试都将正确解锁许可证。要在多个类之间共享安装/拆卸代码,可以使用xUnit的 引述: 要使用收集装置,需要执行以下步骤:
- 创建fixture类,并将启动代码放入fixture类构造函数中
- 如果fixture类需要执行清理,请在fixture类上实现IDisposable,并将清理代码放入Dispose()中 方法
- 创建集合定义类,使用[CollectionDefinition]属性对其进行修饰,并为其指定一个唯一的名称,该名称将 确定测试集合
- 将ICollectionFixture添加到集合定义类
- 使用您为测试提供的唯一名称,将[Collection]属性添加到将成为集合一部分的所有测试类 集合定义类的[CollectionDefinition]属性
- 如果测试类需要访问fixture实例,则将其添加为构造函数参数,并自动提供
我一直在寻找相同的答案,而此时的xUnit文档对于如何实现类固定装置和集合固定装置非常有帮助,它们为开发人员提供了类或类组级别的各种设置/拆卸功能。这与Geir Sagberg的答案一致,并给出了很好的框架实现来说明它应该是什么样子 收集装置 何时使用:当您希望创建单个测试上下文并在多个测试类中的测试之间共享它,并在测试类中的所有测试完成后将其清除时 有时,您会希望在多个测试类之间共享一个fixture对象。用于类fixture的数据库示例是一个很好的示例:您可能希望使用一组测试数据初始化数据库,然后将该测试数据保留在适当的位置以供多个测试类使用。您可以使用xUnit.net的collection fixture功能在多个测试类中的测试之间共享单个对象实例 要使用收集装置,需要执行以下步骤: 创建fixture类,并将启动代码放入fixture类构造函数中。 如果fixture类需要执行清理,请在fixture类上实现IDisposable,并将清理代码放入Dispose()方法中。 创建集合定义类,使用[CollectionDefinition]属性对其进行修饰,并为其指定一个唯一的名称来标识测试集合。 将ICollectionFixture添加到集合定义类。 将[Collection]属性添加到将成为集合一部分的所有测试类,
[Collection("TestEngine")]
public class MyTests
{
[Collection("TestEngine")]
public class MyTests
{
public MyTests(TestEngineInitializer initializer)
{
}