golang, how to play with mock data?

At work, many companies require efficiency and automatic testing

During the actual landing process, it is found that the current service may rely on the data and interfaces of other services for unit testing and automated testing

In the process of single test or automation, the test may fail or block due to other service reasons or environmental factors

This is a problem that must be solved. We can use the mock tool provided by golang to complete it. We can pile data and mock data in some necessary places

What is gomock?

It is an official framework for mock data

The official also provides mockgen tool to help us generate test code

The project address on github is: github com/golang/mock

The official introduction of gomock is as follows:

gomock is a mocking framework for Go programming language. It integrates well with Go's built-in test package, but it can also be used in other environments.

How to use gomock?

Using gomock is also very simple. First go get the corresponding tools gomock and mockgen

go get -u github.com/golang/mock/gomock
go get -u github.com/golang/mock/mockgen

You can write a demo to practice

The directory structure is like this

gomock_test
├── go.mod
├── go.sum
├── main.go
└── myfunc
    ├── mock_myfunc.go
    ├── myfunc.go
    ├── myuser.go
    └── myuser_test.go

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-5r1xnval-1640937816719)( https://upload-images.jianshu.io/upload_images/26809252-166fbe55a12ae403.png?imageMogr2/auto -orient/strip%7CimageView2/2/w/1240)]

  • mock_myfunc.go is generated using the mockgen tool
  • myfunc.go is mainly used to simulate the underlying implementation of the call
  • myuser.go is mainly to call myfunc Interface in go
  • myuser_test.go is the corresponding single test file

myfunc.go

  • Write an interface with a GetInfo() string method to simulate obtaining information
package myfunc

type MyFunc interface {
	GetInfo() string
}

myuser.go

  • Call myfunc Go, call the interface to get information
package myfunc

func getUser(m MyFunc) string {
	user := m.GetInfo()
	return user
}

Generation of mock file

mock_myfunc.go

This file is not written by ourselves, but generated by mockgen tool. The generation method is as follows:

In myfunc Execute the following statement under the same level directory of go, and fill in the source file and target file to generate a new mock file

mockgen -source=myfunc.go -destination=mock_myfunc.go

We can see the help document of mockgen and other parameters for us to use

# mockgen
mockgen has two modes of operation: source and reflect.

Source mode generates mock interfaces from a source file.
It is enabled by using the -source flag. Other flags that
may be useful in this mode are -imports and -aux_files.
Example:
        mockgen -source=foo.go [other options]

Reflect mode generates mock interfaces by building a program
that uses reflection to understand interfaces. It is enabled
by passing two non-flag arguments: an import path, and a
comma-separated list of symbols.
Example:
        mockgen database/sql/driver Conn,Driver

  -aux_files string
        (source mode) Comma-separated pkg=path pairs of auxiliary Go source files.
  -build_flags string
        (reflect mode) Additional flags for go build.
  -copyright_file string
        Copyright file used to add copyright header
  -debug_parser
        Print out parser results only.
  -destination string
        Output file; defaults to stdout.
  -exec_only string
        (reflect mode) If set, execute this reflection program.
  -imports string
        (source mode) Comma-separated name=path pairs of explicit imports to use.
  -mock_names string
        Comma-separated interfaceName=mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix.
  -package string
        Package of the generated code; defaults to the package of the input with a 'mock_' prefix.
  -prog_only
        (reflect mode) Only generate the reflection program; write it to stdout and exit.
  -self_package string
        The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude.
  -source string
        (source mode) Input Go source file; enables source mode.
  -version
        Print version.
  -write_package_comment
        Writes package documentation comment (godoc) if true. (default true)
2021/10/30 16:43:25 Expected exactly two arguments

Generally used more is

  • -Source source file
  • -Destination destination file
  • -imports depends on the package that needs to be import ed
  • -build_flags parameters passed to the build tool
  • -aux_ The files interface attaches files when there is more than one file
  • -Package sets the package name of the mock file. If it is not set, the package name of the mock file is mock by default_ Enter the package name of the file

The mock files generated by the above instructions are as follows:

  • NewMockMyFunc

Create a new mock instance

  • EXPECT

An object that allows the caller to indicate the intended use

  • GetInfo

The basic method of mock, that is, the method we need to mock

Specific how to use

myuser_test.go

  • myuser. The single test file corresponding to go uses the mock method
package myfunc

import (
	"fmt"
	"testing"
	gomock "github.com/golang/mock/gomock"
)

func Test_getUser(t *testing.T) {
	mockCtl := gomock.NewController(t)
	mockMyFunc := NewMockMyFunc(mockCtl)
	mockMyFunc.EXPECT().GetInfo().Return("xiaomotong")
	v := getUser(mockMyFunc)
	if v == "xiaomotong" {
		fmt.Println("get user right!")
	} else {
		t.Error("get error user")
	}
}

Seeing the above single test files, we can't understand the difference. Let's see how we can write a single test without mock

package myfunc

import (
	"fmt"
	"testing"
	gomock "github.com/golang/mock/gomock"
)

func Test_getUser(t *testing.T) {
    m := myfunc.CreateMyFunc() // That is, you need to create an object yourself
	v := getUser(m)
	if v == "xiaomotong" {
		fmt.Println("get user right!")
	} else {
		t.Error("get error user")
	}
}

m := myfunc. When createmyfunc() sees the above sentence, it creates the corresponding object, and then passes the object as a parameter into the getUser function. Under normal circumstances, there is no problem with single test

However, if the MyFunc object is not coded due to external dependencies at this time, it can not block our unit tests

At this time, it is particularly important to use the top mock scheme. You can use the mock method to mock a MyFunc object and set the return value, such as:

mockCtl := gomock.NewController(t)
mockMyFunc := NewMockMyFunc(mockCtl)
mockMyFunc.EXPECT().GetInfo().Return("xiaomotong")

The result of executing the above code is as follows:

> go test
get user right!
PASS
ok      mygomock/myfunc 0.427s

Interested friends can use it and become more familiar with it

What are the benefits of using gomock?

  • gomock implements a relatively complete interface based Mock function, which can be well integrated with the built-in testing package of Golang, and can also be used in other testing environments
  • Learning cost is low and can be started soon

Tools need to be used to give play to their value. What you need can be used

Welcome to like, follow and collect

My friends, your support and encouragement are the driving force for me to insist on sharing and improve quality

Well, that's all for this time

Common technologies are open, and our mentality should be open. Embrace change, live in the sun and strive to move forward.

Keywords: Java Go Back-end

Added by klapy on Tue, 04 Jan 2022 10:01:59 +0200