何时使用 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,我在这种情况下的最佳实践是使用文档中描述的 TestFixtureSetUp
、TestFixtureTearDown
、SetUp
和 TearDown
方法。
我认为,当我不将 nUnit 测试夹具视为普通类时,它也会对我有所帮助,即使您使用该构造定义它也是如此。我认为它们是固定装置,这让我克服了心理障碍,让我忽略了这个问题。
【讨论】:
请注意xUnit article 暗示Setup
s(以及构造函数)通常是一个坏主意,这使得测试代码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 属性
何时使用inputRef.current而不是this.inputRef React.js?