xUnit.net – 在ALLtesting前后运行代码

TL; DR – 我正在寻找xUnit相当于MSTest的AssemblyInitialize (也就是我喜欢的ONEfunction)。

具体而言,我正在寻找它,因为我有一些selenium烟雾testing,我希望能够运行没有其他的依赖。 我有一个Fixture,将为我启动IisExpress并在处置时将其杀死。 但是在每次testing之前这样做会极大地增加运行时间。

我想在testing开始时触发一次该代码,并在最后处置它(closures进程)。 我怎么能这样做?

即使我可以通过编程访问诸如“目前正在运行多lesstesting”之类的东西,我也可以想出一些东西。

截至2015年11月,xUnit 2已经发布,所以在testing之间共享function是一种规范的方法。 这里logging在案。

基本上你需要创build一个类来完成这个工作:

  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属性的虚拟类。 这个类允许Xunit创build一个testing集合,并将使用给定的fixture来进行集合的所有testing类。

  [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. } 

然后,您需要将集合名称添加到所有testing类中。 testing类可以通过构造函数接收灯具。

  [Collection("Database collection")] public class DatabaseTestClass1 { DatabaseFixture fixture; public DatabaseTestClass1(DatabaseFixture fixture) { this.fixture = fixture; } } 

这比MsTests AssemblyInitialize更详细一些,因为你必须在每个testing类上声明它属于哪个testing集合,但是它也更具可调性(并且使用MsTests,你仍然需要在你的类上放一个TestClass)

注意:样本已从文档中提取。

创build一个静态字段并实现一个终结器。

您可以使用xUnit创build一个AppDomain来运行testing程序集并在完成时将其卸载的事实。 卸载应用程序域将导致终结器运行。

我正在使用此方法来启动和停止IISExpress。

 public sealed class ExampleFixture { public static ExampleFixture Current = new ExampleFixture(); private ExampleFixture() { // Run at start } ~ExampleFixture() { Dispose(); } public void Dispose() { GC.SuppressFinalize(this); // Run at end } } 

编辑:在您的testing中使用ExampleFixture.Current访问灯具。

今天在框架中做不到这一点。 这是一个计划2.0的function。

为了在2.0之前完成这个工作,它需要你在框架上执行重要的重新架构,或者编写自己的认可你自己的特殊属性的跑步者。

我使用AssemblyFixture ( NuGet )。

它所提供的是提供一个IAssemblyFixture<T>接口,它将取代IClassFixture<T> ,将对象的生存期作为testing程序集。

例:

 public class Singleton { } public class TestClass1 : IAssemblyFixture<Singleton> { readonly Singletone _Singletone; public TestClass1(Singleton singleton) { _Singleton = singleton; } [Fact] public void Test1() { //use singleton } } public class TestClass2 : IAssemblyFixture<Singleton> { readonly Singletone _Singletone; public TestClass2(Singleton singleton) { //same singleton instance of TestClass1 _Singleton = singleton; } [Fact] public void Test2() { //use singleton } } 

你的构build工具是否提供这样的function?

在Java世界中,当使用Maven作为构build工具时,我们使用构build生命周期的适当阶段 。 例如,在您的情况下(使用类似Selenium的工具进行验收testing),您可以充分利用pre-integration-testpost-integration-test阶段,以便在integration-test之前/之后启动/停止Web应用程序。

我很确定可以在您的环境中设置相同的机制。

你可以使用IUseFixture接口来实现这一点。 你所有的testing也必须inheritanceTestBase类。 您也可以直接从您的testing中使用OneTimeFixture。

 public class TestBase : IUseFixture<OneTimeFixture<ApplicationFixture>> { protected ApplicationFixture Application; public void SetFixture(OneTimeFixture<ApplicationFixture> data) { this.Application = data.Fixture; } } public class ApplicationFixture : IDisposable { public ApplicationFixture() { // This code run only one time } public void Dispose() { // Here is run only one time too } } public class OneTimeFixture<TFixture> where TFixture : new() { // This value does not share between each generic type private static readonly TFixture sharedFixture; static OneTimeFixture() { // Constructor will call one time for each generic type sharedFixture = new TFixture(); var disposable = sharedFixture as IDisposable; if (disposable != null) { AppDomain.CurrentDomain.DomainUnload += (sender, args) => disposable.Dispose(); } } public OneTimeFixture() { this.Fixture = sharedFixture; } public TFixture Fixture { get; private set; } } 

编辑:解决新的夹具为每个testing类创build的问题。