在TDD重构之后编写更多单元测试

Sam*_*les 3 c# tdd unit-testing

这是我们一遍又一遍地讨论过的事情,人们的意见在这方面似乎有很大不同.

基本问题,在进行TDD时,应该在循环的重构步骤之后添加额外的单元测试.我不是在谈论你的下一个测试开始你的下一个周期,而是测试以涵盖由于重构而产生的任何变化.

这可能最好用现实生活中的例子来解释.在TDD周期的绿色之后,我们有以下代码:

    public bool ShouldVerifyDomain
    {
        get
        {
            return this.Orders.SelectMany(x => x.Items).Any(x => x.Product.RequiresDomainVerification);
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,我看看这个,并想一想,linq语句可能有点整洁,更容易阅读,而不是违反Demeter,让我们重构一下.所以我创建了以下内容Order:

 public bool HasItemsThatRequireDomainVerification
 {
     get
     {
          return this.Items.Any(x => x.Product.RequiresCascadeDomainVerification);
     }
 }
Run Code Online (Sandbox Code Playgroud)

并修改ShouldVerifyDomain为:

  public bool ShouldVerifyDomain
  {
      get
      {
           return this.Orders.Any(x => x.HasItemsThatRequireDomainVerification);
      }
  }
Run Code Online (Sandbox Code Playgroud)

好吧,那看起来好一点,我对此感到高兴.让我们继续我的列表上的下一个测试......但是......等等,我们现在HasItemsThatRequireDomainVerification通过另一个对象上的属性测试该属性....是一个真正的单元测试还是我应该添加一个测试(s )直接测试HasItemsThatRequireDomainVerification.

我的感受?我不认为它会增加很多价值.我认为这会增加套件的维护负担,花费时间并没有真正让我们对未来的变化更有信心.

它能给我们带来什么?公共界面的"文档" Order.

思考?

Dav*_*vid 8

您的重构步骤是否添加或更改功能?如果是这样,那么这是一个无效的重构步骤.您应该先退出这些更改,然后再为新功能添加测试.

但是,在你的例子中,我认为不一定是这种情况.你所做的只是提取方法非常相似.您将现有逻辑合并到另一个位置,并从现有位置调用该位置.现有的测试仍在测试中.

在重构之后,如果您担心需要添加更多测试,那么首先应该看看您的测试覆盖率.如果你仍然处于100%(或者与重构前一样接近它),那么你可能仍然很好.另一方面,如果重构添加了测试未涵盖的代码路径,那么您有一些选择:

  • 您的代码是否需要这些代码路径?如果是这样,测试是不够的.您应该退出重构,为新代码路径添加失败的测试,然后添加新的代码路径.
  • 如果你的代码并不需要这些代码路径,那么他们为什么呢?摆脱它们.

你问的问题非常类似于一个关于测试覆盖率的古老问题,这个问题以多种形式提出:

  • 我应该测试私人会员吗?
  • 我应该为每种方法编写单独的测试吗?
  • 每个对象的每个成员都应该进行测试吗?

和所有事情一样,答案总是"取决于".应该测试所有代码,但每行代码都不需要自己的测试.例如,假设我在类上有一个属性:

public class Customer
{
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我是否需要编写一个实例化a的测试,向其Customer写入一个Name值,然后声明它可以读回相同的值?显然不是.如果失败则会出现严重错误.但是,这行代码是否应该通过测试覆盖?绝对.某处应该有一个测试,这使得使用的CustomerName.如果没有,如果系统中没有测试使用此属性,则测试不完整或系统实际上不需要此属性,应将其删除.

换句话说,当你编写测试时,你并没有真正测试代码.您正在测试系统的功能.实现该功能的代码与测试分开并且并行.这两个人不需要了解彼此的大量细节.如果某些内容的外部可见功能发生变化,则测试应更改为匹配(并验证)它.如果外部可见功能未更改,则测试也不必更改.他们仍然应该验证相同的功能.