【问题标题】:Unittest method calling other Unittest methods. Bad Design?Unittest 方法调用其他 Unittest 方法。糟糕的设计?
【发布时间】:2019-08-21 10:53:37
【问题描述】:

我正在为没有任何自动化测试的遗留应用程序编写单元测试。在写作时,我意识到如果不重构,单元测试会变得非常大。所以如果没有重构,我需要很多函数来保持我的测试可读。 可以在测试中使用“排列”或“设置”方法来保持它们的可读性吗?或者是我的测试复杂。这是一些伪代码。

[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);
}

...

【问题讨论】:

  • 您的示例和上下文不是很清楚,但setup 方法在单元测试中当然很常见。测试代码就是代码,所以应该重构,去掉重复。

标签: unit-testing tdd legacy


【解决方案1】:

将帮助函数作为测试代码的一部分是很常见的。它可能有益的一些情况是:

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

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

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

【讨论】:

    猜你喜欢
    • 2021-10-14
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多