教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 golang单元测试之mock

golang单元测试之mock

发布时间:2022-03-11   编辑:jiaochengji.com
教程集为您提供golang单元测试之mock等资源,欢迎您收藏本站,我们将为您提供最新的golang单元测试之mock资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg>

搞单元测试,如果碰到这些情况:
1,一个函数,内部包含了很多并且很深的调用,但是如果单单测这个函数,其实实现的功能很简单。
2,一个函数,包含了其他还未实现的调用。
3,函数内部对数据的要求极为苛刻。

那么这时候就可以考虑使用mock来处理。

mock,简而言之就是可以通过注入我们所期望返回的数据,或者我们所期望传递的参数,来避免上面那些情况,其原理则是通过反射来实现。

这次就来看看golang的mock,gomock
gomock是go官方提供的mock解决方案,主要分为两部分:gomock库和mock代码生成工具mockgen。

使用举例:

<pre class="prettyprint"><code class=" hljs lasso">package metal <span class="hljs-keyword">type</span> Imetal interface { GetName() <span class="hljs-built_in">string</span> SetName(<span class="hljs-built_in">string</span>) <span class="hljs-built_in">string</span> } <span class="hljs-keyword">type</span> Metal struct { Name <span class="hljs-built_in">string</span> Exchange <span class="hljs-built_in">string</span> } func (<span class="hljs-built_in">self</span> Metal) GetName() <span class="hljs-built_in">string</span> { <span class="hljs-keyword">if</span> <span class="hljs-built_in">self</span><span class="hljs-built_in">.</span>Name<span class="hljs-subst">==</span><span class="hljs-string">""</span>{ <span class="hljs-keyword">return</span> <span class="hljs-string">"none"</span> } <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span><span class="hljs-built_in">.</span>Name } func (<span class="hljs-built_in">self</span> <span class="hljs-subst">*</span>Metal) SetName(brand <span class="hljs-built_in">string</span>) <span class="hljs-built_in">string</span> { <span class="hljs-built_in">self</span><span class="hljs-built_in">.</span>Name<span class="hljs-subst">=</span>brand <span class="hljs-keyword">return</span> <span class="hljs-string">"done"</span> }</code></pre>

我现在有一个package,其包含了IMetal接口,这个接口下面有两个方法,现在针对这两个方法来进行mock,ps:gomock只支持interface方法的mock。

在mock之前,需要先通过mockgen来生成mock代码,我的源就是上面的IMeta接口。

简单介绍一下mockgen:
它有两种工作模式---source和reflect

source模式
mockgen -source=foo.go [other options]
根据源文件来生成,源文件是包含了一个或多个interface的文件。

reflect模式
mockgen src/package Conn,Driver
一个文件定义了多个interface而你只想对部分interface进行mock,或者interface存在嵌套,使用reflect模式

mock代码生成好之后,接下来是写测试函数。

<pre class="prettyprint"><code class=" hljs avrasm">package metal import ( <span class="hljs-string">"mock_metal"</span> <span class="hljs-string">"github.com/golang/mock/gomock"</span> <span class="hljs-string">"testing"</span> <span class="hljs-string">"fmt"</span> ) func GetMetalName(mi Imetal) string { mi<span class="hljs-preprocessor">.GetName</span>() return mi<span class="hljs-preprocessor">.GetName</span>() } func SetMetalName(mi Imetal,name string) string { return mi<span class="hljs-preprocessor">.SetName</span>(name) } func TestMetalName(t *testing<span class="hljs-preprocessor">.T</span>) { mockCtl := gomock<span class="hljs-preprocessor">.NewController</span>(t) defer mockCtl<span class="hljs-preprocessor">.Finish</span>() mockMetal := mock_metal<span class="hljs-preprocessor">.NewMockImetal</span>(mockCtl) //mock_metal就是生成的mock代码,以包的形式存在 m:=new(Metal) mockCtl<span class="hljs-preprocessor">.RecordCall</span>(m,<span class="hljs-string">"GetName"</span>)<span class="hljs-preprocessor">.Times</span>(<span class="hljs-number">1</span>) mockCtl<span class="hljs-preprocessor">.Call</span>(m,<span class="hljs-string">"GetName"</span>) <span class="hljs-keyword">call</span>:=mockMetal<span class="hljs-preprocessor">.EXPECT</span>()<span class="hljs-preprocessor">.GetName</span>()<span class="hljs-preprocessor">.Return</span>(<span class="hljs-string">"apple"</span>) mockMetal<span class="hljs-preprocessor">.EXPECT</span>()<span class="hljs-preprocessor">.GetName</span>()<span class="hljs-preprocessor">.Return</span>(<span class="hljs-string">"peer"</span>)<span class="hljs-preprocessor">.After</span>(<span class="hljs-keyword">call</span>) //注入期望的返回值 mockedBrand:=GetMetalName(mockMetal) mockMetal<span class="hljs-preprocessor">.EXPECT</span>()<span class="hljs-preprocessor">.SetName</span>(gomock<span class="hljs-preprocessor">.Eq</span>(<span class="hljs-string">"al"</span>))<span class="hljs-preprocessor">.Do</span>(func(format string) { //入参校验 fmt<span class="hljs-preprocessor">.Println</span>(<span class="hljs-string">"recv param :"</span>,format) })<span class="hljs-preprocessor">.Return</span>(<span class="hljs-string">"setdone"</span>) mockMetal<span class="hljs-preprocessor">.EXPECT</span>()<span class="hljs-preprocessor">.SetName</span>(gomock<span class="hljs-preprocessor">.Any</span>())<span class="hljs-preprocessor">.Do</span>(func(format string) { //入参不做校验 fmt<span class="hljs-preprocessor">.Println</span>(<span class="hljs-string">"recv param :"</span>,format) })<span class="hljs-preprocessor">.Return</span>(<span class="hljs-string">"setdone"</span>) mockedSetName:=SetMetalName(mockMetal,<span class="hljs-string">"al"</span>) fmt<span class="hljs-preprocessor">.Println</span>(mockedSetName) if <span class="hljs-string">"peer"</span>!=mockedBrand{ t<span class="hljs-preprocessor">.Error</span>(<span class="hljs-string">"Get wrong name:"</span>, mockedBrand) } if <span class="hljs-string">"setdone"</span>!=mockedSetName{ t<span class="hljs-preprocessor">.Error</span>(<span class="hljs-string">"Set wrong name:"</span>, mockedSetName) } }</code></pre>

然后执行go test即可,会发现这些被mock的函数会按照我们定义的行为来执行。

附带两个gomock的官方资料,基本上看完了就可以上手了。

https://godoc.org/github.com/golang/mock/gomock
https://github.com/golang/mock/blob/master/sample/user_test.go

第一个是gomock库的所有方法说明,第二个是官方的例子,里面有如何进行gomock的方法使用。

到此这篇关于“golang单元测试之mock”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Go单元测试:为什么stub叫做桩函数,mock叫做模拟接口?
golang单元测试之mock
搞定Go单元测试(一)——基础原理
[gist]用 jest 轻松测试 JavaScript
Golang单元测试:有哪些误区和实践?
go mockweb接口_golang 单元测试(gotests、mockery自动生成)
学习单元测试,告别祈祷式编程
Python和单元测试那些事儿
优雅的使用Go进行单元测试
用cmd运行python文件_怎么用cmd运行python文件

[关闭]
~ ~