在 xUnit 中管理多级收集装置/从 NUnit 移植

Managing multiple levels of collection fixtures in xUnit / porting from NUnit

我们目前正在将 NUnit 测试迁移到 xUnit。在我们之前的测试中,我们有多个级别的测试基地:

public class TestBase {
    protected ICacheManagerFactory _cacheManagerFactory;
    [OneTimeSetup]
    public void OneTimeSetup()
    {
        //Setup code
    }
}

public class ControllerTestBase : TestBase {
    [OneTimeSetup]
    public void OneTimeSetup()
    {
        //Setup code
        _cacheManagerFactory.SomeSetup();
    }
}

我们想在 xUnit 中复制该功能,这样原始的 TestBase 设置就不会 运行 多次。我们正在尝试像这样在集合中使用集合:

public sealed class CollectionFixtureBase {
    public ICacheManagerFactory CacheManagerFactory;
    public CollectionFixtureBase
    {
        //Setup code
    }
}

[Collection("CollectionFixtureBase")]
public sealed class ControllerCollectionFixture {
    public CollectionFixtureBase CollectionBase;
    public ControllerCollectionFixture(CollectionFixtureBase collectionBase)
    {
        CollectionBase = collectionBase
        CollectionBase.CacheManagerFactory.SomeSetup();
    }
}

(为简洁起见,我省略了集合夹具定义)

但是,当我们 运行 这段代码时,我们遇到了依赖注入错误:

System.AggregateException : One or more errors occurred. Collection fixture type 'Instanda.UnitTests.New.Collections.ControllerCollectionFixture' had one or more unresolved constructor arguments: CollectionFixtureBase collectionFixture The following constructor parameters did not have matching fixture data: ControllerCollectionFixture collectionFixture

我们是不是走错了路?我们可以从基础 类 继承,但我的印象是这会导致基础代码多次 运行?是否有其他方法来获得此功能?

当试图理解 CollectionFixture 作为新手时(尤其是在 NUnit、JUnit 和其他系统中有经验的人,这些系统往往会导致测试 Classes 中的 class 层次结构),我建议在 https://xunit.net/docs/shared-context 上进行大量传球;该模型非常不同且微妙。好的,现在你从那里回来了:TL;DR

  1. xUnit Collection Fixtures 实现的主要目的是确保一次只有一个测试可以使用共享的东西

  2. xUnit 管理它们:

    一个。让他们(一次)

    b。在每次测试 运行 之前通过 IUse* 将它们传递给您的测试 class(记住 NUnit 和 xUnit 之间的关键区别在于每次 Fresh Fixture

  3. 在不再classes/tests需要它们时处理它们

  4. 就是这样 - 没有 class 等级等

Collection Fixtures 是最强大的构造,很难手动编写,并且相对常见,例如包装数据库,不要忘记 Class Fixtures - 它们是典型的 OneTimeSetup 的工作马,就像在 OP

在对如何跨测试 Classes 管理共享装置进行高级分解时,您要做的主要事情是让尽可能多的东西 运行 并发和独立( xUnit 运行s multiple Test Classes default concurrently; Collection Fixtures is the key way to constrain this)

在使用 NUnit 模式和 OneTimeSetup/Setup/Teardown 属性获得的典型 class 层次结构之间进行迁移时,一般高级建议:

  • 尝试将辅助逻辑拆分为单独的 Fixture,以清晰的方式管理一个方面;通常在 NUnit 中,您的灯具会倾向于 'blend'
  • 你在 base classes 中使用 NUnit 所做的大多数事情映射到 xUnit 中的 Class fixtures(xUnit 在每次测试之前制作并提供给测试 Class)
  • stuff 绝对只能是通常映射到 Collection Fixtures 中的一个
  • advanced/rare:对于可以安全共享的任何其他助手,通常使用 Class 固定装置,其中一些静态方面由静态 ctor 或其他一些守卫初始化以管理并发 initialisation/access 安全状态
  • 它绝对不是非法的,但应该成为一种非常罕见的情况,你最终使用基础 classes 进行测试(你将东西放在构造函数中并 IDisposable.Dispose 替换设置和拆卸方法)