1

所以,我一直在阅读有效地使用旧代码。它很棒,涵盖了许多很酷的技术,这些技术也可以“安全”地用于未经测试的代码。

我最喜欢的部分之一是建议在存在麻烦的依赖项时扩展您打算测试的类。例如

class FooBar
{
  public List<Foo> ReadFoos()
  {
    var s=new SqlConnection(Config.SomeConntectionStirng);
    s.Read("Foo")....
  }
}

被重构为

class FooBar
{
  public List<Foo> ReadFoos()
  {
    var s=MyConnection();
    s.Read("Foo")....
  }
  protected virtual IConnection MyConnection()
  {
    return new SqlConnection(Config.SomeConnectionString);   
  }
}

然后为了测试它,你会像这样继承它:

class TestableFooBar : FooBar
{
  protected override IConnection MyConnection()
  {
    return new MockConnection();
  }
}

并在扩展类上进行测试。

现在,我的问题。可以这样做并且以后不重构吗?我这么说的主要原因是因为这对于一些通常难以单元测试而不会使调用 API 更难使用的代码很有用。在公共 API 上,您肯定希望它尽可能简单。那么,按设计保留这样的事情是否可行?

4

1 回答 1

5

从设计的角度来看,“提取和覆盖”可能不是您选择完成的地方,但它归结为更改现有代码与添加新功能的预算。虽然您可能也不热衷于更改公共 API,但有一些技术可以保留 API,同时还允许更适当的依赖注入。我相信这本书讨论了一种这样的技术,它是一个默认构造函数,它提供对重载的依赖(下面的示例),另一种可以简单地使用依赖注入容器。

public class Foo
{
     IDependency dependency;

     public Foo() // preserves API
          : this(new Dependency())
     {
     }

     internal Foo(IDependency dependency) 
     {
         this.dependency = dependency;
     }

注意:在此示例中,我将第二个构造函数标记为内部,但您可以将其保留为公共,特别是如果您希望程序集之外的类可以选择提供该依赖项。为了简单的可测试性,我喜欢 internal 修饰符,因为我会通过“InternalsVisibleTo”程序集属性将内部暴露给我的单元测试项目。这使您可以保持 API 干净,但也可以对诸如此类的技术以及内部辅助类具有最大的可测试性。

于 2013-02-14T22:31:35.557 回答