单元测试:“如果您进行重构并且没有合作者,这是代码的味道”?


9

我正在阅读Roy Osherove撰写的《单元测试的艺术》。我在第7.2节“编写可维护的测试”中,作者对代码气味有此说明:

注意:当您重构内部状态以使其对外部测试可见时,是否可以将其视为代码异味(表示代码设计或逻辑中可能存在问题的迹象)?当您重构以暴露协作者时,这不是代码的味道。如果您要重构并且没有协作者,这是一种代码味道(因此您不需要存根或模拟任何东西)。

编辑:作者所说的“合作者”是依赖。他关于依赖项的一些示例是访问数据库或访问OS的文件系统的类。他在这里定义存根并开始使用“协作者”一词:

存根是用于现有的可控替换依赖性(或 合作者在系统中)。

作者没有此代码气味的示例,并且我在理解/描绘其外观时遇到困难。有人可以再解释一下,也许可以提供一个具体的例子?


我认为这里的混乱源于“合作者”一词。我必须承认,我也不确定他在这方面的含义。
rossipedia 2012年

@Bryan Ross,我用作者如何使用“合作者”一词更新了帖子。谢谢!
程序员

Answers:


3

我认为这就是作者的意思。

在我的代码示例中,我有一个计时窗口,该窗口需要一个输出量加上一个开始和停止时间。目的是在24小时的时间跨度内绘制输出窗口。当开始时间大于停止时间时,会添加皱纹,因为这是一个跨越午夜的计时窗口。

您可以编写可以充分利用对象的单元测试,而无需暴露私有变量。这些私密性和时间跨度是他在公开内部进行单元测试时所指的合作者。根据这本书,暴露这些内部结构不会带来代码异味,因为它们是合作者。

公开double output会带来代码异味,因为它不是协作者-这是类本身明确隐藏的元素,其中包含条件逻辑GetOutput来确定应返回的内容。

深入了解布尔/时间跨度将使单元测试更加全面。他说这很好。
深入研究双重output可能需要在单元测试中附加逻辑,以反映GetOutput正在执行的操作。这就是他所指的代码味道。

公共类TimeWindow
{
  私人布尔isConst;
  私人布尔跨度
  私有TimeSpan start1;
  私人TimeSpan stop1;
  私有TimeSpan start2;
  私人TimeSpan stop2;
  私有双输出;

  公共TimeWindow(翻倍,TimeSpan开始,TimeSpan停止)
  {
    输出=输出;

    if(开始==停止)
      isConst = true;
    否则if(开始>停止)
    {
      spansMidnight = true;
      start1 =午夜;
      stop1 =停止;
      start2 =开始;
      stop2 =午夜;
    }
    其他 
    {
      start1 =开始;
      stop1 =停止;
    }
  }

  公共double GetOutput(TimeSpan time)
  {
    //这里关于如何返回的逻辑
    ...
    返回输出;
  }

}

0

假设我们有一个域类,并且该域类使用存储库直接了解持久层,该存储库用于公开实例级“保存”方法,域类上的对象可以调用该方法来持久化更改无需了解机制就可以完成(这是否是“好的”设计,这是另一天的讨论)。重构类以将该存储库作为属性和/或构造函数参数公开,从而允许传递经过模拟的存储库以确保可以进行正确的调用,这不仅对测试而且对总体可维护性而言都是一件好事。

现在,这是一个域类,它具有状态数据。让我们暂时假设其中一个有状态属性具有一个后备字段,并且该属性访问器根据当前输入项来测试新输入是否有效(也许新值永远不能小于旧输入值)。您需要测试此验证,但是您发现这样做需要访问后备字段以设置一个初始值,然后尝试覆盖该初始值。这应该是一个危险信号;如果测试需要访问支持字段(这是一个实现细节; 没有消费者应该不断必须知道它的存在)以使对象进入测试的一致状态,那么生产代码将如何获得一致的对象?如果有一种生产代码可以执行测试所要执行的相同操作的方法,则该测试可能应该模仿这种方式。如果生产代码没有有效的方法使对象进入此状态,那么为什么要测试这种情况?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.