何时使用 TestFixtureSetUp 属性而不是默认构造函数?

Posted

技术标签:

【中文标题】何时使用 TestFixtureSetUp 属性而不是默认构造函数?【英文标题】:When do I use the TestFixtureSetUp attribute instead of a default constructor? 【发布时间】:2010-09-17 18:47:50 【问题描述】:

NUnit 文档没有告诉我何时使用带有 TestFixtureSetup 的方法以及何时在构造函数中进行设置。

public class MyTest

    private MyClass myClass;

    public MyTest()
    
        myClass = new MyClass();
    

    [TestFixtureSetUp]
    public void Init()
    
        myClass = new MyClass();
    

TestFixtureSetup 与默认构造函数有什么好的/坏的做法,或者没有任何区别?

【问题讨论】:

由于这是一个经常被问到的问题,请考虑this 和this(MSTest 的讨论相同)。但要注意夹具设置对测试可读性的副作用(查看here 和here)。 只有我的 1 美分:这在有许多测试的基类时很有用。派生类将自动运行父类中定义的 TestFixtureSetup。除非你专门调用构造函数,否则你不能这样做(这可能是也可能不是问题,取决于你有多少派生类) 【参考方案1】:

为什么需要在测试类中使用构造函数?

我使用[SetUp][TearDown] 标记的方法在每次测试之前和之后执行代码,同样[TestFixtureSetUp][TestFixtureTearDown] 标记的方法在所有测试之前和之后只执行一次代码夹具已运行。

我猜你可能可以用 [TestFixtureSetUp] 代替构造函数(虽然我没有尝试过),但这似乎只是打破了标记方法提供的明确约定。

【讨论】:

我不知道为什么需要构造函数,但我也不知道为什么需要 TestFixtureSetUp。我知道 setup、teardown 和 testfixtureteardown 属性。我只是不知道构造函数和 testfixturesetup 属性的区别。 只是为了回答你的问题。如果您有参数化的测试夹具,则需要在测试类中使用构造函数。【参考方案2】:

我认为这是 nUnit 团队尚未解决的问题之一。然而,优秀的xUnit project 看到了这个确切的问题,并决定在test fixture initialization 上使用构造函数是一件好事。

对于 nunit,我在这种情况下的最佳实践是使用文档中描述的 TestFixtureSetUpTestFixtureTearDownSetUpTearDown 方法。

我认为,当我不将 nUnit 测试夹具视为普通类时,它也会对我有所帮助,即使您使用该构造定义它也是如此。我认为它们是固定装置,这让我克服了心理障碍,让我忽略了这个问题。

【讨论】:

请注意xUnit article 暗示Setups(以及构造函数)通常是一个坏主意,这使得测试代码difficult to follow,而不是构造函数比Setup 更好s。然而,无参数构造函数是那些真正需要它的人的最后手段。另请参阅:Test styles and avoiding setup/teardown【参考方案3】:

我经常想知道[TestFixtureSetUp] 的需求是什么,因为有一个简单、易于理解的一流语言结构可以做完全相同的事情。

我的偏好是使用构造函数,以利用 readonly 关键字确保成员变量无法重新初始化。

【讨论】:

readonly 关键字不能确保成员不会被修改。如果成员是类,则可以在测试中修改类的内部状态,并将此状态传递到下一个测试方法(因为nunit不会在每次测试运行之间重新创建类)【参考方案4】:

我认为我有一个否定的好答案 - 使用构造函数而不是属性的原因是当您在测试类之间具有继承时。

只有一个带有[TestFixtureSetup] 注释的方法会被调用(仅在具体类上),但其他夹具初始化器不会。在这种情况下,我宁愿将初始化放在构造函数中,它具有明确定义的继承语义:)

【讨论】:

这在 NUnit 2.5 之后发生了变化现在所有用 [TestFixtureSetup] 注释的方法都将被调用。【参考方案5】:

您可以在构造函数中使用 [TestFixtureSetup] 做的一件事是从 [TestFixture] 接收参数。

如果您想参数化您的测试夹具,那么您将必须使用构造函数进行至少 一些 的设置。到目前为止,我只将它用于集成测试,例如用于测试具有多个数据提供者的数据访问层:

[TestFixture("System.Data.SqlClient",
  "Server=(local)\\SQLEXPRESS;Initial Catalog=MyTestDatabase;Integrated Security=True;Pooling=False"))]
[TestFixture("System.Data.SQLite", "Data Source=MyTestDatabase.s3db")])]
internal class MyDataAccessLayerIntegrationTests

    MyDataAccessLayerIntegrationTests(
        string dataProvider,
        string connectionString)
    
        ...
    

【讨论】:

【参考方案6】:

构造函数和标有[TestFixtureSetUp]属性的方法是有区别的。根据 NUnit 文档:

建议构造函数不要有任何副作用,因为 NUnit 可能在会话过程中多次构造对象。

因此,如果您有任何昂贵的初始化,最好使用TestFixtureSetUp

【讨论】:

这是假设标记为 TestFixtureSetUp 的方法是静态的。否则不可能更频繁地调用构造函数,除非测试实例被丢弃而不被 NUnit 使用,我会怀疑。【参考方案7】:

构造函数和SetUp方法的使用不同: 构造函数只运行一次。 但是,SetUp 方法会在每个测试用例执行之前运行多次。

【讨论】:

你指的是[SetUp],而OP指的是[TestFixtureSetUp]【参考方案8】:

[TestFixtureSetUp][TestFixtureTearDown] 用于整个测试类。只运行一次。

[SetUp][TearDown] 适用于每种测试方法(测试)。为每个测试运行。

【讨论】:

【参考方案9】:

构造函数和 TestFixtureSetUp 之间的一个重要区别是,至少在 NUnit 2 中,构造函数代码实际上是在测试枚举上执行的,而不仅仅是测试运行,所以基本上你希望将 ctor 代码限制为仅填充只读,即参数、值.任何会导致副作用或进行任何实际工作的东西都需要包装在 Lazy 中或在 TestFixtureSetUp / OneTimeSetUp 中完成。因此,您可以将构造函数视为仅用于配置测试的地方。而 TestFixtureSetUp 是测试夹具的位置,即在测试运行之前系统所需的初始状态被初始化。

【讨论】:

这是一个很好的观点,不确定现在有多相关,但值得考虑。

以上是关于何时使用 TestFixtureSetUp 属性而不是默认构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

何时使用 GetXXX() 方法以及何时使用 Getter 属性

何时在传递给 Vue 组件的属性上使用“:”?

何时使用inputRef.current而不是this.inputRef React.js?

何时向托管对象添加类别以及何时使用瞬态属性?

何时使用 WPF 依赖属性与 INotifyPropertyChanged

Spring事务的事务属性