How to do mock a function using gomock in Go?

huangapple go评论89阅读模式
英文:

How to do mock a function using gomock in Go?

问题

我是你的中文翻译助手,以下是翻译好的内容:

我刚开始学习Go语言,正在做一个小的简单项目,并且养成测试习惯来学习。但是在使用模拟(mock)设置测试时遇到了麻烦,特别是在设置模拟对象时。

sample/sample.go

package sample

import (
    "fmt"
    "net/http"
)

func GetResponse(path, employeeID string) string {
    url := fmt.Sprintf("http://example.com/%s/%s", path, employeeID)
    // 在这里进行一些请求
    // 然后将resp.Body转换为字符串并保存到value中
    return value
}

func Process(path, employeeID string) string {
    return GetResponse(path, employeeID)
}

sample/sample_test.go

package sample_test

import (
    "testing"
    
    "github.com/example/sample" // 想要对这个包中的一些方法进行模拟
)

func TestProcess(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()
    
    sample.MOCK()SetController(ctrl)
    sample.EXPECT().GetResponse("path", "employeeID").Return("abc")

    v := sample.GetResponse("path", "employeeID")
    fmt.Println(v)
}

每次我运行

go test

都会得到错误信息

undefined: sample.MOCK
undefined: sample.EXPECT
  1. 有人能指出我做错了什么吗?我需要先初始化一个模拟对象吗?在模拟方法之前?

  2. 如果我将GetResponse方法设置为私有[getResponse],我就无法对其进行模拟,对吗?

感谢所有的帮助..谢谢!

英文:

I am new to Go and doing small simple project + doing testing habit to learn.. but I am having trouble in setting up test using mock. Specifically in setting up the mock object

sample/sample.go

package sample
import (
    "fmt"
    "net/http"
)

func GetResponse(path, employeeID string) string {
    url := fmt.Sprintf("http://example.com/%s/%s", path, employeeID)
    // made some request here
    // then convert resp.Body to string and save it to value
    return value
}

func Process(path, employeeID string) string {
    return GetResponse(path, employeeID)
}

sample/sample_test.go

package sample_test
import (
     "testing"
     
     "github.com/example/sample" // want to mock some method on this package
)

func TestProcess(t *testing.T) {
     ctrl := gomock.NewController(t)
     defer ctrl.Finish()
     
     sample.MOCK()SetController(ctrl)
     sample.EXPECT().GetResponse("path", "employeeID").Return("abc")

     v := sample.GetResponse("path", "employeeID")
     fmt.Println(v)
}

Everytime I run this with

go test

I always get error

undefined: sample.MOCK
undefined: sample.EXPECT
  1. Anyone could point out what am I doing wrong? do I need to initialize a mock object first? before mocking the method?

  2. If I make GetResponse to be private [getResponse], I wont be able to mock it right?

Appreciate the all help.. Thanks!

答案1

得分: 7

我不是gomock的专家,但在阅读了gomock GoDoc页面之后,我发现你的代码存在几个问题。首先,显然你不能使用gomock来模拟包函数(就像你试图对sample.GetResponse做的那样),只能模拟接口。其次,根据“标准用法”,你需要:

  1. 定义一个你想要模拟的接口(比如FooInterface)
  2. 使用mockgen从该接口生成一个模拟对象
  3. 使用函数NewMockFooInterface()创建一个模拟对象mockObj
  4. 然后,mockObj将具有你想要调用的方法(即EXPECT())
英文:

I am not a gomock expert, but after reading the gomock GoDoc page, I see several issues with your code. First, you apparently can't use gomock to mock package functions (as you are trying to do with sample.GetResponse), only interfaces. Second, according to "standard usage", you have to

  1. define an interface (e.g. FooInterface) that you want to mock
  2. use mockgen to generate a mock from that interface
  3. create a mockObj using the function NewMockFooInterface()
  4. mockObj will then have the methods you want to call (i.e. EXPECT())

答案2

得分: 5

测试和覆盖率:

  1. 接口 -> 接口是一组命名的方法签名。接口是Go语言的一个重要部分。使用基于接口的结构是一种很好的实践,可以确保代码与特定的依赖关系耦合度较低。此外,接口还允许进行高效、简单和结构化的测试。
  2. GoMock是Go语言的一个模拟框架。它在github.com/golang组织中享有某种官方地位。它与Go的内置测试包很好地集成在一起,并提供了灵活的期望API。
  3. 我们需要gomock包(由我们的依赖管理机制处理)以及mockgen代码生成工具(将包含mockgen.exe的文件夹设置为PATH变量)进行测试。
    使用GoMock遵循四个基本步骤:
  4. 使用mockgen为要模拟的接口生成一个模拟对象。
  5. 在测试中,创建一个gomock.Controller的实例,并将其传递给模拟对象的构造函数以获取一个模拟对象。
  6. 在模拟对象上调用EXPECT()来设置它们的期望和返回值。
  7. 在模拟控制器上调用Finish()来断言模拟对象的期望(我们使用testify来进行断言)。

有关如何使用mockgen为我们的接口生成模拟对象的更多信息,请参考→ https://github.com/golang/mock
一个使用mockgen命令生成模拟接口文件的示例 ->

mockgen -destination={将生成的模拟对象放入文件中} -package={为此包生成模拟对象} {为此接口生成模拟对象}

更多信息请参考 -> https://blog.codecentric.de/en/2017/08/gomock-tutorial/

英文:

Testing and Coverage :

  1. Interfaces --> Interfaces are named collections of method signatures. Interfaces are a key part of Go.
    Using an interface based structure is a great practice to ensure your code is less coupled to any specific dependency. Also, interfaces allow for efficient ,easy and structured testing.
  2. GoMock is a mocking framework for the Go programming language.It enjoys a somewhat official status as part of the github.com/golang organization. It integrates well with Go's built-in testing package, and provides a flexible expectation API.
  3. We need gomock package(handled by our dependency management mechanism) as well as the mockgen code generation tool(folder containing mockgen.exe to be set to PATH variable) for our testing
    Usage of GoMock follows four basic steps:
  4. Use mockgen to generate a mock for the interface you wish to mock.
  5. In your test, create an instance of gomock.Controller and pass it to your mock object’s constructor to obtain a mock object.
  6. Call EXPECT() on your mocks to set up their expectations and return values
  7. Call Finish() on the mock controller to assert the mock’s expectations(we use testify to make assertions)

For more on how to generate mocks for our interfaces using mockgen , please refer → https://github.com/golang/mock
an example of mockgen command to generate mock interfaces file ->

mockgen -destination={put the generated mocks in the file} -package={generate mocks for this package} {generate mocks for this interface}

For more info refer --> https://blog.codecentric.de/en/2017/08/gomock-tutorial/

huangapple
  • 本文由 发表于 2014年3月8日 04:26:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/22260037.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定