【问题标题】:Dependency injection compared to global interfaces [closed]与全局接口相比的依赖注入[关闭]
【发布时间】:2021-03-24 09:38:24
【问题描述】:

我认为依赖注入而不是全局变量的原因之一是在测试期间很难模拟全局变量。但是假设我将全局声明为接口,我可以避免这个问题。

package restclient
type HTTPClient interface {
    Do(req *http.Request) (*http.Response, error)
}

var (
    Client HTTPClient
)

func init() {
    Client = &http.Client{}
}

在上面的示例中,我正在创建一个全局接口并将其初始化为一个 http 客户端。所以每当我想进行 REST 调用时,我都会使用这个接口。 现在在我的测试用例中,如果我想模拟 http 客户端,我需要做的就是

restclient.Client = new(RestclientMock)

那么考虑到简单性,这种使用全局接口的方法不是比使用依赖注入更好吗?

【问题讨论】:

  • 开场白对我来说听起来很奇怪:一个精心设计的 Go 程序不包含全局变量,也不使用 DI——相反,您使用接口来为您的关键对象指定行为契约'想要有多个可交换的实现,包括用于测试,然后你有简单无聊的代码,它创建必要类型的对象并将它们传递给创建其他对象的代码等 - 所有一直到“叶子”对象。后者是 DI fluff 在其掩护下所做的。
  • 这太奇怪了。为什么要模拟 http.Client?
  • @Volker 你将如何测试一段调用外部 API 的代码。如果我不模拟它,它会使实际的 http 调用本身正确吗?
  • «如何测试一段调用外部 API 的代码。»通常你会在 httptest.Server 的帮助下做到这一点。
  • 当然你不会调用一些有副作用的外部API。当然,您调用外部 API 的本地存根或伪造。问题不是“在测试期间对非无副作用的 3rd 方 API 进行实际 HTTP 调用有什么问题?”但是“在测试期间进行实际的 HTTP 调用有什么问题?”因为那个 call 是你可以用你奇怪的模式省略的。对不起,如果我不清楚。按照 kostix 的说明设置本地存根/伪造文件。不要嘲笑。

标签: unit-testing go dependency-injection interface global


【解决方案1】:

当考虑并行运行多个测试时,这种方法关于测试的问题开始变得清晰。

一个测试会将全局变量设置为能够使用它进行测试,并且在测试时,它会被下一个测试覆盖,从而导致两个测试的行为不可预测。它们现在相互影响,使用相同的依赖实例。

注意:实际上,您甚至可以在不启用并行执行测试的情况下遇到该问题。特别是如果依赖项具有内部 goroutines,这些 goroutines 可能会超出为它们创建的测试的执行。

【讨论】:

  • 这是一个很好的观点。
猜你喜欢
  • 1970-01-01
  • 2013-11-07
  • 1970-01-01
  • 2017-06-10
  • 2018-01-06
  • 2023-04-06
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多