golang-Mock对单元测试的作用

为什么要Mock

  在一个复杂项目中,项目可能依赖于多个组件(DB,Cache,File等)。这些依赖都属于项目中的强依赖,如果没有这些组件,项目是不完整的,或者说某个功能是运行不了的。   单元测试有两个目标,一个是幂等,一个是稳定。

  幂等:重复运行一个测试的case,每次的结果都是一样的

  稳定:单元测试相互隔离,在任何时间,任何函数,任何环境都能独立的运行

  那要实现这个目标,因为我们有这么多依赖,如果直接写单元测试,调用db,这样单元测试肯定是不稳定的,因为会依赖于网络的传输。那要怎么写能实现稳定的单元测试呢?

  对于强依赖的项目,如何实现稳定这个目标呢?因为我们有这么多强依赖,如果直接写单元测试,调用DB,这样的单元测试是不稳定的,因为会依赖于网络的传输,如果DB刚好挂了呢?那么怎样才能实现一个不依赖组件的稳定单元测试呢?

要解决这个问题,我们需要用到Mock,单元测试的过程中需要用到mork机制

什么是Mock

github地址:

快速Mock函数

    为一个函数打桩 为一个方法打桩

  下面我们来看一下Mock,打桩可以理解为用一个函数A替换成函数B,函数B就是原函数,函数A就是一个打桩函数。

  以函数打桩为例,有两个方法,一个是Patch,入参是原函数,replacement是我们需要打桩的函数,另一个是unpatch,是为了在保证在测试结束以后把这个桩卸载掉。

  monkey包的实现主要是在运行时,通过go的unsafe包,将内存中函数的地址替换成运行时函数地址,这样其实最终在测试的时候调用的是打桩函数,就实现了Mork的功能

做个测试

不用Mock

  可以看到,这里的单元测试是依赖于本地log文件的,一旦log文件被篡改,被删除,那么这个单元测试就失败了

func ReadFirstLine() string {
          
   
	buf, err := ioutil.ReadFile("log")
	if err != nil {
          
   
		panic(err)
	}
	return string(buf)
}
func TestProcessFirstLine(t *testing.T) {
          
   
	firstLine := ReadFirstLine()
	assert.Equal(t, "wxf", firstLine)
}

使用Mock

  这里对ReadFirstLine进行打桩,让其始终返回"wxf",通过一个Mork,就实现了单元测试不对本地文件的强依赖。这样我们的单元测试就可以在任何时间,任何环境去执行,完全不依赖于本地文件,测试依然能够正常运行

func TestProcessFirstLineWithMock(t *testing.T) {
          
   
	monkey.Patch(ReadFirstLine, func() string {
          
   
		return "wxf"
	})
	defer monkey.Unpatch(ReadFirstLine)
	line := ReadFirstLine()
	assert.Equal(t, "wxf", line)
}
经验分享 程序员 微信小程序 职场和发展