我正在编写测试,我必须将模拟传递给特定方法。我想知道,通过构造函数传递它或直接传递给有问题的方法有什么好处。或者这不重要。
例如
通过构造函数传递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。
答案 0 :(得分:3)
在这种情况下,IClock是一个隐藏的单例 - 它从底层操作系统生成当前日期时间。如果您想编写可靠的验收测试,则需要在这些测试中删除日期时间提供程序。
因此,您需要将此依赖关系一直暴露到模块边界,然后将一个公共日期时间源注入您的模块(甚至整个系统)。在编写验收测试时,您有时会将此“IClock”日期时间源存根。
这将允许您回答以下问题:
在构造函数签名或方法签名中具有IClock依赖关系将清楚地向用户记录您的方法或对象是否依赖于日期时间。在尝试理解对象的行为时,对日期时间的依赖通常是至关重要的,因此应该突出。通常避免任何隐藏此依赖关系的东西(例如在重载的方法定义中提供默认的日期时间源),因为这会阻止您编写上述我所描述的验收测试。
在将依赖项传递给构造函数或方法之间进行选择通常取决于方法对系统其余部分的职责。这些方法构成了公共协议,对象将使用该协议与正在运行的系统中的对等方进行通信,而构造函数参数是此特定实现执行其角色所需的依赖项。
问自己这些问题:
答案 1 :(得分:1)
具体取决于谁知道IClock
:在构建User
时是否可用,或者在调用UpdateUser
时是否可用?
如果您将其传递给构造函数,则可以传递User
对象,任何人都可以调用UpdateUser
,但如果您通过UpdateUser
传递,则使用该方法的任何人必须持有IClock
参考。
答案 2 :(得分:1)
将依赖项(即IClock
)传递给constuctor,即构造函数注入通常意味着这是给定类的整个对象的必需依赖项。将依赖关系传递给类的方法,即方法注入只使这个特定的方法依赖于它。还有另外两种可能性:对属性注入依赖性(属性注入,即类的对象的可选依赖项)和很少使用的环境上下文。
因此,这是团队中代码风格的品味,设计和协议的更多问题。
在您的示例IClock
中,User
的对象不需要依赖项,因此方法注入更合适。