Unit testing 依赖NUnit单元测试的顺序是一种糟糕的形式吗

Unit testing 依赖NUnit单元测试的顺序是一种糟糕的形式吗,unit-testing,nunit,Unit Testing,Nunit,我一直在疯狂地创建单元测试,发现我经常不得不在一个测试中设置一些东西,而在上一个测试中我刚刚删除了这些东西。在一个测试(例如插入测试)中创建某个内容(例如数据库记录),然后将其用于以后的测试(例如删除测试)是否合理?还是每一次测试都应该完全独立 你能确定NUnit中测试的顺序吗?还是它们总是按字母顺序进行的 注意:我特别询问一个测试文件中的测试顺序。不跨测试文件或以任何方式更全局 更新:感谢所有回答的人-有很多好的答案,团队的感觉非常一致。我选择了约翰·诺兰的答案,因为他提供了最完整的解释和大量

我一直在疯狂地创建单元测试,发现我经常不得不在一个测试中设置一些东西,而在上一个测试中我刚刚删除了这些东西。在一个测试(例如插入测试)中创建某个内容(例如数据库记录),然后将其用于以后的测试(例如删除测试)是否合理?还是每一次测试都应该完全独立

你能确定NUnit中测试的顺序吗?还是它们总是按字母顺序进行的

注意:我特别询问一个测试文件中的测试顺序。不跨测试文件或以任何方式更全局


更新:感谢所有回答的人-有很多好的答案,团队的感觉非常一致。我选择了约翰·诺兰的答案,因为他提供了最完整的解释和大量的链接。正如你可能已经猜到的,我一直很想打破这条规则,尽管我认为它可能有点像约翰所说的“臭”。还要感谢Fortyrunner添加了单元测试标签。

我真的不需要依赖测试的顺序。相反,我将把公共设置代码拉入一个单独的方法中,并从简单的测试和更复杂的测试中调用它。或者,只需在删除测试开始时调用插入测试本身。

我会将每个测试视为完全独立于任何其他测试。即使您可以强制执行测试的顺序,但当测试必须更改时,这将是一场维护噩梦。

仔细研究,以允许您指定将在夹具中的任何测试之前执行的功能。这允许您只执行一次公共设置,它将始终运行,无论您是运行一个测试,还是套件中的所有测试。

不幸的是,单元测试的运行顺序是不可预测的,或者至少将来可以更改。例如,单元测试框架将被更改,因此每个测试将在单独的线程中执行。 所以从我的观点来看,使用测试顺序是不合理的。
另一方面,您可以创建一组小型独立测试来测试代码的小部分,然后创建一个或多个大型测试,这些测试将按特定顺序运行小型测试。

单元测试旨在独立运行,而不是作为顺序脚本运行。如果您确实需要它们按顺序运行,请将它们收集到单个测试函数中


如果您的单元测试受到影响,那么当您认为您正在进行单元测试时,您可能正在进行集成测试。如果您在大多数单元测试中使用SQL数据库,那么实际上您是在与数据访问层进行集成测试。

我强烈建议您将所有单元测试独立起来

您的业务逻辑/数据库结构等可能会随着时间的推移而改变,因此您最终将不得不替换或重写(甚至放弃)现有的单元测试-如果您有多个其他测试,取决于您要替换的测试,这可能会造成不必要的麻烦,因为您还必须完成所有其他测试,并检查这些测试是否仍按预期工作


此外,一个失败的单元测试不应该能够拖累许多其他的单元测试(这些单元测试本身可能可以很好地工作)。

依赖于测试的顺序,表明您在测试中保持状态。这是

一种更干净的测试方法是,您只依赖于要检查其行为的单个功能。通常情况下,您需要使用其他对象来测试方法的功能

考虑进行单元测试的一个好方法是模式

下面是卡尔·塞奎因的精彩免费电影片段。我已经说明了安排、行动和主张

[TestFixture] public class CarTest 
{ 
    [Test] public void SaveCarCallsUpdateWhenAlreadyExistingCar()   
    {
         //Arrange
         MockRepository mocks = new MockRepository();
         IDataAccess dataAccess = mocks.CreateMock<IDataAccess>();   
         ObjectFactory.InjectStub(typeof(IDataAccess), dataAccess); 
         //Act
         Car car = new Car(); 
         Expect.Call(dataAccess.Save(car)).Return(389); 
         mocks.ReplayAll(); 
         car.Save(); 
         mocks.VerifyAll(); 
         // Assert
         Assert.AreEqual(389, car.Id); 
         ObjectFactory.ResetDefaults();
    } 
}
[TestFixture]公共类CarTest
{ 
[测试]当已存在CAR()时,公共无效存储CAR调用supdate
{
//安排
MockRepository mocks=新建MockRepository();
IDataAccess dataAccess=mocks.CreateMock();
InjectStub(typeof(IDataAccess),dataAccess);
//表演
汽车=新车();
Expect.Call(dataAccess.Save(car)).Return(389);
mocks.ReplayAll();
car.Save();
mocks.VerifyAll();
//断言
AreEqual(389,car.Id);
ResetDefaults();
} 
}

如果您有状态测试(数据库工作中的一个常见问题,我不在状态测试时就是这样做的),那么在我看来,避免测试文件中的顺序并不是绝对必要的。但是,您必须认识到,如果您有两个测试,测试2取决于测试1是否通过,那么如果测试1失败,您将获得“灾难性”的双重失败,因为测试2没有预期的设置(而且,如果您认为测试2取决于测试1是否通过,您还需要担心测试1失败后测试2是否通过)

这就是为什么您希望测试尽可能独立于文件内和文件间


依赖不同文件中(组)测试之间的顺序是非常不明智的。

很好地报告并解释您的最新想法。很好,谢谢你,乔恩。我认为这是一个社区,如果社区要发展壮大,需要一定程度的关注。ObjectFactory.ResetDefaults()指令实际上是“断言”的一部分吗?我考虑过这个问题,我认为它应该被称为Arrange,Act,Assert,Clean或者Arrange,Act,Assert,Reset?诸如此类的事情,或者:安排、行动、断言、打乱?虽然我基本上同意你的观点,但在某些情况下,一个测试必须依赖另一个测试,并且/或者使用模拟对象可能会破坏测试过程的关键。例如,一个团队需要将函数拆分为比合理的更为谨慎的部分,或者在数据库后端版本之间进行测试时。在这些情况下,我喜欢使用可以设置的静态变量