xUnit.net:全局设置+拆卸?

这个问题是关于unit testing框架xUnit.net 。

我需要在执行任何testing之前运行一些代码,并且在完成所有testing之后还要执行一些代码。 我认为应该有某种属性或标记接口来表示全局初始化和终止代码,但找不到它们。

或者,如果我以编程方式调用xUnit,我也可以通过以下代码实现我想要的function:

static void Main() { try { MyGlobalSetup(); RunAllTests(); // What goes into this method? } finally { MyGlobalTeardown(); } } 

任何人都可以提供一个关于如何声明或以编程方式运行一些全局设置/拆卸代码的提示吗?

据我所知,xUnit没有全局初始化/拆卸扩展点。 但是,创build一个很容易。 只需创build一个实现IDisposable的基类testing类,并在构造函数中进行初始化,并在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 } 

但是,每个调用都会执行基类build立和拆卸代码。 这可能不是你想要的,因为它不是很有效率。 更优化的版本将使用IClassFixture<T>接口来确保全局初始化/拆卸function只被调用一次。 对于这个版本,你不会从你的testing类扩展一个基类,而是实现IClassFixture<T>接口,其中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 void SetFixture(TestsFixture data) { } } 

导致TestsFixture的构造TestsFixture只对每个被testing的类运行一次。 这取决于你想要在两种方法之间进行select。

我晚了一点,但是我正在寻找相同的答案,在这个时候,xUnit文档对于如何实现Class Fixtures和Collection Fixtures非常有帮助,这些Fixture和Collection Fixtures为开发人员提供了广泛的设置/拆卸function在class级或class级一级。 这与Geir Sagberg的回答是一致的,并给出了很好的框架实现来说明它应该是什么样子。

https://xunit.github.io/docs/shared-context.html

Collection Fixtures什么时候使用:当你想创build一个testing上下文并在多个testing类中的testing之间共享它,并且在testing类的所有testing完成之后清理它。

有时你会想要在多个testing类中共享一个夹具对象。 用于类装置的数据库示例就是一个很好的例子:您可能希望用一组testing数据初始化数据库,然后将testing数据保留在适当位置以供多个testing类使用。 您可以使用xUnit.net的集合夹具function在多个testing类中的testing中共享一个对象实例。

要使用收集夹具,您需要采取以下步骤:

创build夹具类,并将启动代码放在夹具类的构造函数中。 如果fixture类需要执行清理,则在fixture类上实现IDisposable,并将清理代码放在Dispose()方法中。 创build集合定义类,使用[CollectionDefinition]属性对其进行装饰,给它一个唯一的名称来标识testing集合。 将ICollectionFixture <>添加到集合定义类。 使用提供给testing集合定义类的[CollectionDefinition]属性的唯一名称,将[Collection]属性添加到将成为集合一部分的所有testing类。 如果testing类需要访问fixture实例,请将其添加为构造函数参数,并自动提供。 这是一个简单的例子:

 public class DatabaseFixture : IDisposable { public DatabaseFixture() { Db = new SqlConnection("MyConnectionString"); // ... initialize data in the test database ... } public void Dispose() { // ... clean up test data from the database ... } public SqlConnection Db { get; private set; } } [CollectionDefinition("Database collection")] public class DatabaseCollection : ICollectionFixture<DatabaseFixture> { // This class has no code, and is never created. Its purpose is simply // to be the place to apply [CollectionDefinition] and all the // ICollectionFixture<> interfaces. } [Collection("Database collection")] public class DatabaseTestClass1 { DatabaseFixture fixture; public DatabaseTestClass1(DatabaseFixture fixture) { this.fixture = fixture; } } [Collection("Database collection")] public class DatabaseTestClass2 { // ... } 

xUnit.net对待集合夹具的方式与类夹具非常相似,除了集合夹具对象的生命周期更长:它是在集合中的任何testing类中运行任何testing之前创build的,并且不会被清理直到集合中的所有testing类已经完成运行。

testing集合也可以用IClassFixture <>来装饰。 xUnit.net把这个看作是testing集合中的每个单独的testing类都用类装饰来装饰的。

testing集合也会影响xUnit.net并行运行testing的方式。 有关更多信息,请参阅并行运行testing。

重要提示:夹具必须与使用它们的testing相同。

有一个简单的解决scheme。 使用Fody.ModuleInit插件

https://github.com/Fody/ModuleInit

这是一个nuget包,当你安装它时,它会向项目中添加一个名为ModuleInitializer.cs的新文件。 在这里有一个静态方法,在编译之后被编译到程序集中,并且在程序集加载之后以及运行之前立即运行。

我用这个解锁软件许可证到我已经购买的图书馆。 我总是忘记在每个testing中解锁许可证,甚至忘记从可以解锁它的基类中派生出testing。 写这个库的明亮的火花,而不是告诉你,这是许可证locking引入微妙的数值错误,导致testing失败或通过时,他们不应该。 你永远不会知道你是否正确地解锁了图书馆。 所以现在我的模块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"); } } 

并且放入此程序集的所有testing都将为其正确解锁许可证。

要在多个类之间共享SetUp / TearDown代码,可以使用xUnit的CollectionFixture 。

引用:

要使用收集夹具,您需要采取以下步骤:

  • 创build夹具类,并将启动代码放在夹具类的构造函数中。
  • 如果fixture类需要执行清理,则在fixture类上实现IDisposable,并将清理代码放在Dispose()方法中。
  • 创build集合定义类,使用[CollectionDefinition]属性对其进行装饰,给它一个唯一的名称来标识testing集合。
  • 将ICollectionFixture <>添加到集合定义类。
  • 使用提供给testing集合定义类的[CollectionDefinition]属性的唯一名称,将[Collection]属性添加到将成为集合一部分的所有testing类。
  • 如果testing类需要访问fixture实例,请将其添加为构造函数参数,并自动提供。

应该有bootstrap选项在其他任何地方运行代码。 至less有PHPUnit。 你没有提到你使用的是什么框架。

我不知道在所有testing后运行代码的方法。 但是你可以在一个运行testing的包装脚本中执行它,然后运行你需要的任何东西。