refactoring - 做BDD时如何重构和发现依赖关系

标签 refactoring tdd mocking bdd

执行 BDD 意味着从上到下,因此我们首先为顶级功能编写测试。现在要设置测试,您通常需要设置一些模拟而不是真正的依赖。您如何知道需要哪些依赖项,需要什么样的服务?我无法弥补如何定义这个级别的依赖关系。在经典的 TDD 自下而上中,它就像将现有的 impl 重构为依赖对象一样简单。

BDD 和模拟是否意味着我们需要预先构建和粗略设计完整的依赖关系图?

那么重构呢?似乎没有地方可以将您的 impl 分解为依赖项,因为您已经定义了这些依赖项。

例如,我有一个定时缓存功能要实现。 我的测试应该是:

  • 如果未缓存,则通过存储调用返回值
  • 返回值,如果缓存,则不进行存储调用
  • 如果超时则通过存储调用返回值

这是否意味着我需要识别所有潜在的依赖项并准备模拟?我应该验证从 xall 返回的值,还是仅验证预期的依赖项调用?

最佳答案

我感觉你可能想得有点多了。当事情看起来确实令人困惑时,我通常会提醒自己退后一步并回顾基础知识。首先,我只想做满足要求所需的最低限度的事情。我并不真正关心系统中是否存在许多我尚未意识到的依赖项,因此我以最简单的方式编写测试。如果我发现需要依赖项,我将添加一个模拟并支持允许我的测试运行所需的最小接口(interface)。如果系统稍后需要扩展或支持额外的依赖项,我可以扩展模拟,甚至用我编写的下一个测试的特定内容替换它。我还可能扩展测试,甚至编写新测试来满足我了解和/或清楚的新需求。

重构只是一种表达我打算改变某些东西的奇特方式。这可能是为了优化或以其他方式改进设计,也可能是因为我认为需要打破新的接口(interface)和依赖关系。在这种情况下,我首先在测试中编写更改,甚至可能编写一个新测试,该测试可能会也可能不会取代现有测试。完成后,我将转到我的代码。

无论是自上而下还是自下而上,基本原理都是相同的。问题实际上是什么时候依赖关系会变得不言而喻,然后确定处理它们的策略。当你觉得需要突破一些东西时,我建议你使用一个非常短的峰值。让想法成形,然后在你眼前滚动它,同时向它提出问题。如果感觉追求这个想法是正确的,请编写测试来处理您的尖峰给您带来的问题,然后从那里编写代码。

我有时发现自己有冲动创建大量模拟来处理我能想到的每一种可能的依赖意外情况,每次我回来重复“K.I.S.S.”、“Y.A.G.N.I.”和“Make it”工作,然后让它工作得更好”,一遍又一遍地在我的脑海中,直到我得到这样的信息:我真的不能陷入困境,因为我试图想得太远。

无论您是 TDD、BDD 还是使用任何其他方法,保持事情简单和最少是确保您不会一次处理太多问题的关键。这可能是最需要记住的事情。如果看起来太难以想象,那么问问自己是否有“需求气味”,这表明您需要进一步分解事情。你能把这个“故事”分解成一组包含整体的小故事吗?

我知道我不一定直接回答您提出的问题,但是我认为值得以这种方式编写,因为根据我的经验,当任务很小并且仅限于任务时,依赖关系和重构变得不言而喻一个或两个功能,而当任务过于笼统且难以解释时,就会出现相反的情况。

关于refactoring - 做BDD时如何重构和发现依赖关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7938988/

相关文章:

c++ - 将无状态 C++ 函数从里到外转换为有状态函数

reactjs - Sinon 不会对 react 组件的 getter 进行 stub

javascript - 测试模块的未导出 Node 方法

node.js - 如何检测是否在 node.js 中运行 mocha 测试?

ruby - rspec 中的 double 方法有什么用?

java - 重用循环多维数组的代码

node.js - 重构 Express 中的类似路由,提取回调以分离模块

php - 可以在 Laravel/PHPUnit 中模拟模型方法输出吗?

go - 几乎重复自己

c++ - 使用 Google C++ Mocking Framework (Google Mock) (V1.5) 将任意参数传递给调用的方法