在一个尺度上,是的,模拟旨在用于模拟外部数据源,例如数据库或 Web 服务。但是,在更细粒度的范围内,如果您正在设计松散耦合的代码,那么您可以几乎任意地在代码中画线,以了解在任何时候可能是“外部系统”。拿一个我目前正在做的项目:
当有人尝试签入时,CheckInUi将CheckInInfo对象发送到CheckInMediator对象,该对象使用CheckInValidator对其进行验证,然后如果没问题,它会使用CheckInInfoAdapter用CheckInInfo填充名为Transaction的域对象,然后将Transaction传递给ITransactionDao的实例.SaveTransaction()用于持久性。
我现在正在编写一些自动化集成测试,显然CheckInUi和ITransactionDao是外部系统的窗口,它们应该被嘲笑。但是,谁说 CheckInValidator在某些时候不会调用 Web 服务?这就是为什么当你编写单元测试时,你假设除了你的类的特定功能之外的所有东西都是一个外部系统。因此,在我对CheckInMediator的单元测试中,我模拟了它与之对话的所有对象。
编辑: Gishu 在技术上是正确的,并不是所有的东西都需要被模拟,例如我不模拟CheckInInfo,因为它只是一个数据容器。然而,任何你可以看到作为外部服务的东西(它几乎是任何转换数据或具有副作用的东西)都应该被嘲笑。
我喜欢的一个类比是将适当松散耦合的设计视为一个领域,人们站在它周围玩接球游戏。当有人传球时,他可能会向下一个人扔一个完全不同的球,他甚至可能会连续向不同的人扔多个球,或者扔一个球等着接回来再扔给另一个人。这是一个奇怪的游戏。
现在,作为他们的教练和经理,您当然想检查您的团队作为一个整体是如何运作的,因此您可以进行团队练习(集成测试),但您也可以让每个球员自己练习对抗后卫和投球机(单元测试)嘲笑)。这张照片唯一缺少的部分是模拟期望,所以我们的球上涂上了黑色焦油,所以当它们击中后挡板时会弄脏它。每个逆止器都有一个人瞄准的“目标区域”,如果在练习跑结束时目标区域内没有黑色标记,你就知道有问题了,这个人需要调整他的技术。
真的要花时间正确地学习它,我理解 Mocks 的那一天是一个巨大的 a-ha 时刻。将它与控制容器的反转结合起来,我永远不会回去。
顺便说一句,我们的一个 IT 人员刚进来给了我一台免费的笔记本电脑!