模拟和显式契约 - Dashbit 博客

主要观点

  • 介绍了在 Elixir 中使用模拟(mocks)的相关问题及解决方案,强调模拟应作为名词使用,避免滥用。
  • 以外部 API 为例,说明直接模拟 HTTP 客户端的弊端,如耦合应用、影响测试并发等,提出用配置文件来配置不同环境下的 Twitter 客户端替代模拟。
  • 强调明确的契约(contract)在测试中的重要性,通过定义行为(behaviour)来规范接口,避免模拟实体过度复杂导致的耦合。
  • 指出测试大型系统的关键是找到合适的边界,每个使用模拟的测试都应有集成测试覆盖,以保证系统整体工作正常。
  • 讨论了关于使代码“可测试”、将模拟作为局部变量、将模拟作为名词以及模拟库等常见问题。

关键信息

  • 2015 年 10 月 14 日 José Valim 发表关于 Elixir 中模拟的文章,近 2 年后发布 Mox 库。
  • 模拟是模拟实体以受控方式模仿真实实体行为,应作为名词。
  • 以 Twitter API 为例,直接模拟 HTTP 客户端会导致耦合和测试问题,应通过配置文件选择不同环境的 Twitter 客户端实现。
  • 定义行为规范接口,如在 Elixir 中定义MyApp.Twitter行为,添加@behaviour注解。
  • 测试时需注意边界,每个使用模拟的测试应有集成测试,可利用@tag系统在 ExUnit 中配置测试运行。
  • 对于使代码“可测试”的观点,应注重改进代码设计而非单纯为测试而改变生产代码,配置开销小。
  • 可通过将依赖作为参数传递、定义协议等方式替代依赖配置文件。
  • 模拟库应避免促进不良模式,遵循“模拟作为名词”规则。

重要细节

  • 示例代码中MyApp.MyController通过twitter_api获取 Twitter 客户端并调用其方法,不同环境可配置不同的 Twitter 客户端实现。
  • 强调明确契约可保护避免过度模拟、管理组件间复杂度、便于测试系统隔离复杂组件。
  • 提及外部条件如速率限制可能使某些模拟解决方案不可行,可使用假的 HTTP 客户端或运行模拟服务器。
  • 讨论了不同情况下处理依赖的方式,如作为参数传递、定义协议等,并给出相应示例代码。
阅读 23
0 条评论