【问题标题】:How do I not use an interface when mocking?模拟时如何不使用界面?
【发布时间】:2020-07-27 18:01:54
【问题描述】:

我试图避免使用接口,因为我的用例不需要它(https://www.ardanlabs.com/blog/2016/10/avoid-interface-pollution.html 中也提到过)。但是,要创建一个模拟(使用testify),我不需要一个模拟接口吗?我可以创建一个,但这似乎很乏味。使用我的代码的所有地方都需要编写接口来模拟,而不是实际使用。有解决办法吗?

【问题讨论】:

  • “我的用例不需要它”——不正确。测试需要它。测试是一个用例。
  • 你可以试试pure函数式风格????我认为缺乏泛型并不方便
  • 只是不要使用testify并进行正常测试。

标签: go testify


【解决方案1】:

如果接口的唯一可能用途是用于测试,我同意,那可能是一个糟糕的接口,您应该避免这种情况。

最好的方法是重构您的系统,使其依赖于一个有用的小型接口,而不是一次性“模拟”过分复杂的结构。 net.Listener 接口就是一个很好的例子。建立在net.Listener 之上的系统很容易模拟,是的,但这不是你实现net.Listener 的原因。您使用该接口是因为它允许您交换 许多 个可能的实现,其中之一恰好用于测试。

另一个强大的方法是将函数链接在一起,而不是将功能硬编码为方法。 http.HandlerFunc 就是一个很好的例子,它也展示了出色的界面设计。查看返回http.Handler 的许多“一起单击”函数,而不是一个巨大的“处理程序”结构,然后您必须模拟以进行测试。这是 Go 的最佳 IMO。

记住函数在 Go 中是一等的,你可以通过传递和返回函数而不是将它们绑定到接口来获得很大的灵活性。当你这样做时,你也可以将它们捆绑在一起作为一个结构。这可以提供很多恰好对测试有用的功能。例如,请参阅 tls.Config,它允许您包含自己的 GetCertificate 函数(以及其他函数)。但是tls.Config 结构也有合理的默认值,所以你不必每次都配置每个部分。通过传递tls.Config 的专用版本,您可以在不“模拟”任何东西的情况下测试 TLS 功能。

这里的一致主题是让您的系统在其实现方面具有灵活性,并且作为一个很好的副作用,这使得测试更容易。根据我的经验,这是一种比嘲笑更好的方式来思考问题。

【讨论】:

  • 谢谢!还是在这里学习更多。有趣的是,人们可以将这些功能用作“适配器”。另外,tls.Config 的有趣之处。似乎可以为客户生成“模拟”,因此他们不需要模拟任何东西。
【解决方案2】:

你需要一个接口来模拟,因为模拟你的第二个实现,所以如果你在单元测试中使用模拟,那么你的用例确实需要它。该接口充当占位符,以填充该功能的某些实现。您计划至少有两个这样的实现:一个模拟,一个生产。为了能够在测试中互换使用它们,您必须使用一个接口。

【讨论】:

  • 是的。这是有道理的。
【解决方案3】:

为了减少模拟较大接口的重复次数,似乎可以使用vectra/mockery 之类的东西来生成模拟。然而,这并不是消除对界面的需求的解决方案,但我认为 Rob 在下面提到了一些好的想法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 2013-11-16
    相关资源
    最近更新 更多