重新接线:一条新路子的药剂依赖注入

我一直在工作与灵药了3年全职,虽然我认为这是一个特殊的语言和开发环境,测试故事总觉得不完整的我。缺了点什么。在这篇文章中,我将解释这是什么,我如何试图解决它。

注射嘲弄

虽然我努力用嘲笑的减少,我发现他们仍然在某些情况下非常有用。

药剂之前,我的工作主要是与Java。是好还是坏,在Java中你有多种选项,以依赖注入你的班级。最为显着地,@Autowired它允许你与你的模拟测试期间只需覆盖注释字段。不能再简单。

在药剂的事情有一点不同。这是因为药剂没有类或类字段。模块无国籍。那么,如何在注射药剂的依赖?

让我们看看这个简单例子,探索我们的选项:

defmodule会话高清开始(),英语迎接()结束

函数参数

最简单的方法不需要任何库:假冒使用函数参数的依赖关系。

defmodule会话高清开始lang_mod\\英语lang_mod迎接()结束
defmoduleMyTest的使用ExUnit.Case异步测试“开始/ 0”defmoduleEnglishMock高清迎接(),“天儿真好”结束断言会话开始EnglishMock==“天儿真好”结束结束

虽然许多人(包括我自己)觉得这看起来“古怪”首先,这是无可否认容易做到。

然而,它带有相当多的缺点:

  1. 您的应用程序代码现在散落着测试的担忧。
  2. 导航在你的代码编辑器没有正常工作。
  3. 该模块的用途搜索都比较困难。
  4. 编译器不能向您发出警告的情况下,迎接/ 0在不存在英语模块。

全球覆盖

该药剂库嘲笑(包裹二郎库梅克罩下)允许覆盖全局的任何模块。

defmoduleMyTest的使用ExUnit.Case异步#不同时!进口嘲笑测试“开始/ 0”with_mock英语[迎接FN()- >“天儿真好”结束]断言会话开始()==“天儿真好”结束结束结束

在这里,英语模块被暂时用mock取代了短截线出迎接功能。到目前为止好 - 但它是有代价。一个ExUnit最有价值的功能是运行测试的能力同时。但是,存根出模块全球我们要免于被同时运行这个测试模块(注意异步:假)。这似乎是一个很小的代价,但如果你的应用程序的增长,你可能很快就会有一个缓慢的测试套件发现自己。这是很容易避免!

配置查找

对于药剂或多或少官方嘲讽库MOX

#在test_helper.exs莫克斯defmockEnglishMock对于英语应用put_env:MYAPP:英语EnglishMock
defmodule会话高清开始(),英语()迎接()defp英语(),应用得到:MYAPP:英语英语结束
defmoduleMyTest的使用ExUnit.Case异步真正#同时!进口莫克斯测试“开始/ 0”存根英语:迎接FN- >“天儿真好”结束断言会话开始()==“天儿真好”结束结束

MOX提供由做在应用程序的配置的查找下测试“注入”到该模块的模拟。

其优点是,“奇”功能参数走了,但所有的其他问题仍然存在。但至少它可以同时由于模拟设置运行每个进程(和每个测试模块处于ExUnit它自己的进程)。

联控

我不满足其中的任何选项。所以我尝试一点与药剂元编程,结果是联控

这纯粹是侧重于依赖注入,可与任何嘲弄库中使用,如MOX

#在test_helper.exs莫克斯defmockEnglishMock对于英语
defmoduleMyTest的使用ExUnit.Case异步真正#同时!进口重新接线进口莫克斯联控会话英语EnglishMock#注入!测试“开始/ 0”存根EnglishMock:迎接FN- >“天儿真好”结束断言会话开始()==“天儿真好”结束结束

通过这种方法,我们保持我们的生产代码完全免费的测试问题和测试仍然可以同时运行!

你可以用任何的嘲弄库使用它,而不是仅仅MOX。或者只是存根你自己定义的。它只关心依赖注入。

埃姆,但它是如何工作的?

联控是一个宏,通过导入进口重新接线

让我们看看这里发生了什么代码的宏:

defmoduleConversation.R518高清开始(),EnglishMock迎接()结束别号Conversation.R518会话

首先,它生成一个复制与原来的模块英语参考更换通过EnglishMock。您可能还注意到,该模块名称已更改。由于模块可能在多个地方重新布线,这是应该避免命名冲突。

然后,它增加了一个别名给已重新布线模块下原版的名称。

你可能不知道它是如何产生从原来的一个新的模块。该库通过调用发现模块的源文件路径MODULE_INFO,解析代码与一个ASTCode.string_to_quoted,遍历AST使用更换任何重新布线的依赖Macro.traverse并评价与结果Code.eval_quoted。退房源代码了解详情。

局限性

据我所知,唯一的情况下,你不能使用联控注入你的依赖是当你面对的是已经启动的进程之前您的测试。

举例来说,一种凤凰控制器测试。既然你对服务器进行编写测试(使用ConnCase),在所述控制器的依赖性,不能在事后重新布线。

拉翅

我希望你喜欢这个博客帖子。如果您有任何问题或意见,请发表评论。如果你很好奇,尝试联控你自己。

斯蒂芬·贝肯

通过贸易软件开发人员。大部分时间在不断持续追求简洁,优雅和美丽代码。或者刚刚做的东西在中间。

评论本站由Disqus