Unit testing Unittest方法调用其他Unittest方法。糟糕的设计?

Unit testing Unittest方法调用其他Unittest方法。糟糕的设计?,unit-testing,tdd,legacy,Unit Testing,Tdd,Legacy,我正在为一个没有任何自动测试的遗留应用程序编写单元测试。在写作过程中,我意识到如果不进行重构,单元测试会变得相当大。因此,在不重构的情况下,我需要许多函数来保持测试的可读性。 在测试中使用“排列”或“设置”方法以保持可读性可以吗?还是我的测试很复杂。下面是一些伪代码 [TestMethod] public TestFoo() { Obj1 obj1; Obj2 obj2; ... //arrange SetupObjects(obj1, obj2); //a

我正在为一个没有任何自动测试的遗留应用程序编写单元测试。在写作过程中,我意识到如果不进行重构,单元测试会变得相当大。因此,在不重构的情况下,我需要许多函数来保持测试的可读性。 在测试中使用“排列”或“设置”方法以保持可读性可以吗?还是我的测试很复杂。下面是一些伪代码

[TestMethod]
public TestFoo()
{
   Obj1 obj1;
   Obj2 obj2;
   ...
   //arrange
   SetupObjects(obj1, obj2);

   //act
   Foo.foo( ojb1, obj2);

   //assert
   AssertObjectStates( obj1, obj2);
}

SetupObjects(Obj1 obj1, Obj2 obj2)
{
   CreateAndDoSomethingWithObj1(obj1);
   MockSomethingInObj2(obj2);
}

...

将助手函数作为测试代码的一部分是非常常见的。在某些情况下,这可能是有益的:

  • 测试代码往往是重复的,所以助手函数可以帮助减少代码重复。这简化了具有大量测试的测试套件的创建和维护。(请注意,还有其他机制可以减少代码重复:通常框架提供某种设置和拆卸接口,分别在每次测试之前和之后隐式调用。然而,这些通常会导致Meszaros称之为“神秘来宾”的现象。):在测试代码之外似乎发生了一些神奇的事情。与这些隐式调用的setup和teardown方法不同,显式调用和明确命名的helper函数是一种很好的机制,可以充分利用这两个方面,即避免测试设置中的重复,并且仍然可以很容易地完全理解每个测试。)

  • 封装使用实现细节或非公共接口的测试代码:单元测试是最接近实现的测试级别,如果您的目的也是查找特定于实现的bug,则某些测试将是特定于实现的。还有其他一些情况,测试是建立在玻璃盒(又名白盒)知识的基础上的,比如,当您查看代码覆盖率(例如MC/DC覆盖率)时。然而,这意味着在设计和实现测试时,您必须找到降低测试代码维护工作量的方法。通过封装使用了实现细节的部分测试代码,您最终可以得到一些测试,这些测试也可以找到实现级别的bug,但仍然可以将维护工作保持在可接受的水平上


现在,看看你的代码。这当然只是一个示例代码,因此以下内容对您来说可能是清楚的,即使从代码中看不清楚:在那里使用助手函数的方式是不正确的。函数
SetupObjects
不是描述性的。而且,它分别设置了两个对象,尽管对于测试代码的读者来说,
SetupObjects
似乎会对这两个对象做一些共同的事情。

您的示例和上下文不是很清楚,但是
setup
方法当然在单元测试中非常常见。测试代码只是代码,所以应该对其进行重构,并消除重复。