写点什么

learn go with tests 学习笔记(四)依赖注入

用户头像
半亩房顶
关注
发布于: 2020 年 08 月 07 日
learn go with tests 学习笔记(四)依赖注入

知识点

依赖注入举例

首先我们应该明白什么是控制反转 -> 控制反转(IoC)与依赖注入(DI)

控制反转的目的很简单,即”解耦“

下面用一个打印示例来说明:

func Greet(name string) {
fmt.Printf("Hello, %s", name)
}

那么我们该如何测试它呢?调用 fmt.Printf 会打印到标准输出,用测试框架来捕获它会非常困难。

我们所需要做的就是注入(这只是一个等同于「传入」的好听的词)打印的依赖。

我们的函数不需要关心在哪里打印,以及如何打印,所以我们应该接收一个接口,而非一个具体的类型。

如果我们这样做的话,就可以通过改变接口的实现,控制打印的内容,于是就能测试它了。在实际情况中,你可以注入一些写入标准输出的内容。



如果你看看 fmt.Printf 的源码,你可以发现一种引入(hook in)的方式:

// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}

有意思!在 Printf 内部,只是传入 os.Stdout,并调用了 Fprintf。

os.Stdout 究竟是什么?Fprintf 期望第一个参数传递过来什么?

func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n, err = w.Write(p.buf)
p.free()
return
}

io.Writer 是:

type Writer interface {
Write(p []byte) (n int, err error)
}

如果你写过很多 Go 代码的话,你会发现这个接口出现的频率很高,因为 io.Writer 是一个很好的通用接口,用于「将数据放在某个地方」

所以我们知道了,在幕后我们其实是用 Writer 来把问候发送到某处。我们现在来使用这个抽象,让我们的代码可以测试,并且重用性更好。



依赖注入的作用

  • 测试代码。如果你不能很轻松地测试函数,这通常是因为有依赖硬链接到了函数或全局状态。例如,如果某个服务层使用了全局的数据库连接池,这通常难以测试,并且运行速度会很慢。DI 提倡你注入一个数据库依赖(通过接口),然后就可以在测试中控制你的模拟数据了。

  • 关注点分离,解耦了数据到达的地方和如何产生数据。如果你感觉一个方法 / 函数负责太多功能了(生成数据并且写入一个数据库?处理 HTTP 请求并且处理业务级别的逻辑),那么你可能就需要 DI 这个工具了。

  • 在不同环境下重用代码。我们的代码所处的第一个「新」环境就是在内部进行测试。但是随后,如果其他人想要用你的代码尝试点新东西,他们只要注入他们自己的依赖就可以了。



引用




欢迎大家关注我的公众号,一起探讨技术



发布于: 2020 年 08 月 07 日阅读数: 54
用户头像

半亩房顶

关注

人生那么长,能写多少bug? 2018.11.16 加入

我希望,自己永远是自己。我希望,远离bug。

评论

发布
暂无评论
learn go with tests 学习笔记(四)依赖注入