将接口对象传递给构造函数或方法

时间:2012-07-19 09:08:44

标签: oop testing mocking

我正在编写测试,我必须将模拟传递给特定方法。我想知道,通过构造函数传递它或直接传递给有问题的方法有什么好处。或者这不重要。

例如

通过构造函数传递interface / mock

class User()
{
  IClock clock;

  User(IClock clock) {this.clock = clock;}

  User GetUser(){ ..}
  UpdateUser(User user) {
     ... 
     this.clock.Now();
     ...
  }
}

VS

将interface / mock传递给方法

class User()
{
  User GetUser(){ ..}
  UpdateUser(IClock clock, User user) {
     ... 
     clock.Now();
     ...
  }
}

谢谢!

修改

在这种情况下,IClock将包装DateTime。我这样做是为了测试性。如此有效,我将有一个覆盖,将在其内部构建IClock。

EG。对于方法案例:

UpdateUser(User user) {
  UpdateUser(new Clock(), user);
}

Clock将封装DateTime。

3 个答案:

答案 0 :(得分:3)

在这种情况下,IClock是一个隐藏的单例 - 它从底层操作系统生成当前日期时间。如果您想编写可靠的验收测试,则需要在这些测试中删除日期时间提供程序。

因此,您需要将此依赖关系一直暴露到模块边界,然后将一个公共日期时间源注入您的模块(甚至整个系统)。在编写验收测试时,您有时会将此“IClock”日期时间源存根。

这将允许您回答以下问题:

  • 我的系统是否在闰日上工作?
  • 我的系统是否在午夜工作?
  • 我的系统是否在新年前夕工作?

在构造函数签名或方法签名中具有IClock依赖关系将清楚地向用户记录您的方法或对象是否依赖于日期时间。在尝试理解对象的行为时,对日期时间的依赖通常是至关重要的,因此应该突出。通常避免任何隐藏此依赖关系的东西(例如在重载的方法定义中提供默认的日期时间源),因为这会阻止您编写上述我所描述的验收测试。

在将依赖项传递给构造函数或方法之间进行选择通常取决于方法对系统其余部分的职责。这些方法构成了公共协议,对象将使用该协议与正在运行的系统中的对等方进行通信,而构造函数参数是此特定实现执行其角色所需的依赖项。

问自己这些问题:

  • 这种方法的责任是否必然需要了解日期时间?
  • 或者它是否与此特定对象中方法的特定实现有关,这意味着它需要日期时间?
  • 方法的调用者负责操作此对象的日期时间视图,或模块配置的责任是否合理?
  • 如果我将此对象与同一接口的另一个实现交换,那么该实现不需要此方法的日期时间是否合理?
  • 对象中有多少种方法需要日期时间?他们是否需要相同的日期时间视图?

答案 1 :(得分:1)

具体取决于谁知道IClock:在构建User时是否可用,或者在调用UpdateUser时是否可用?

如果您将其传递给构造函数,则可以传递User对象,任何人都可以调用UpdateUser,但如果您通过UpdateUser传递,则使用该方法的任何人必须持有IClock参考。

答案 2 :(得分:1)

将依赖项(即IClock)传递给constuctor,即构造函数注入通常意味着这是给定类的整个对象的必需依赖项。将依赖关系传递给类的方法,即方法注入只使这个特定的方法依赖于它。还有另外两种可能性:对属性注入依赖性(属性注入,即类的对象的可选依赖项)和很少使用的环境上下文。

因此,这是团队中代码风格的品味,设计和协议的更多问题。

在您的示例IClock中,User的对象不需要依赖项,因此方法注入更合适。

相关问题