![](/img/trans.png)
[英]How do i mock and customise the values of a function imported from a npm package using Jest?
[英]Is it possible to mock a function imported from a package in golang?
我有以下測試方法,它使用從 package 導入的 function。
import x.y.z
func abc() {
...
v := z.SomeFunc()
...
}
是否可以在 golang 中模擬SomeFunc()
?
是的,通過簡單的重構。 創建一個函數類型的zSomeFunc
變量,用z.SomeFunc
初始化,並讓你的包調用它而不是z.SomeFunc()
:
var zSomeFunc = z.SomeFunc
func abc() {
// ...
v := zSomeFunc()
// ...
}
在測試中,您可以將另一個函數分配給zSomeFunc
,一個在測試中定義的函數,並執行測試想要它做的任何事情。
例如:
func TestAbc(t *testing.T) {
// Save current function and restore at the end:
old := zSomeFunc
defer func() { zSomeFunc = old }()
zSomeFunc = func() int {
// This will be called, do whatever you want to,
// return whatever you want to
return 1
}
// Call the tested function
abc()
// Check expected behavior
}
請參閱相關/可能重復: 使用覆蓋信息在 Go 中測試 os.Exit 場景 (coveralls.io/Goveralls)
你可以做的一件事是:
import "x/y/z"
var someFunc = z.SomeFunc
func abc() {
...
v := someFunc()
...
}
在您的測試文件中,您將執行此操作。
func Test_abc() {
someFunc = mockFunc
abc()
}
但是請確保以並發方式執行此操作,如果您有多個TestXxx
函數調用abc
或設置someFunc
,則最好使用帶有someFunc
字段的struct
。
讓函數指針和猴子修補它是其中之一。 但是,當您模擬多個函數時,您將擁有多個函數指針,並且不必要地僅使用函數指針來調用函數。
擁有一個接口並使您的功能成為實現該接口的結構的一部分的更好和推薦的想法。 完成后,您可以使用一些可用於 go 的不錯的工具生成模擬。
我一直在使用這個:
mockgen -source myModule.go -package myPackage -destination myModuleMock.go
您可以通過以下方式安裝它:
go get github.com/golang/mock
雖然創建 package 級別變量是一個可行的選項,但它有一些限制。 舉幾個例子:
t.Parallel()
運行並行測試,因為模擬 function 的不同行為可能存在競爭條件。另一種方法是將要模擬的方法作為 arguments 傳遞給 function 以啟用可測試性。 就我而言,我已經有許多客戶調用此方法,因此,我想避免違反現有合同。 所以,我最終創建了一個包裝好的 function。
例如:
import (
z "x.y.z"
)
//this should replicate the type of function z from x.y.z
type operation func() resp
func wrappedAbc(op operation) {
....
resp := op()
....
}
func Abc() {
wrappedAbc(z)
}
現在為了測試實際邏輯,您將測試對wrappedAbc
而不是abc
的調用,並且您將向它傳遞一個模擬operation
。 這將允許您測試所有業務邏輯,同時不違反 API 與方法Abc
的當前客戶的合同。
mockcompose
使用一種允許您生成mockcompose
類的方法,您可以指示mockcompose
包含您選擇的依賴項閉包(從其他包中導入的任何函數)。 同時,它會生成具有本地覆蓋的主題函數的克隆副本,以便您可以對其進行測試。 您可以使用go generate
嵌入代碼生成過程,因此確保您的克隆副本始終與您的代碼更改同步。
假設您有一個函數functionThatUsesGlobalFunction
在包fmt
中導入Sprintf
。
func functionThatUsesGlobalFunction(
format string,
args ...interface{},
) string {
//
// skip fansy logic...
//
// call out to a global function in fmt package
return fmt.Sprintf(format, args...)
}
您的目標是在被Sprintf
的包fmt
使用Sprintf
測試functionThatUsesGlobalFunction
。
為此,您可以使用mockcompose
配置go generate
,如下所示:
Mocks.go
//go:generate mockcompose -n mockFmt -p fmt -mock Sprintf
//go:generate mockcompose -n mockJson -p encoding/json -mock Marshal
//go:generate mockcompose -n clonedFuncs -real "functionThatUsesGlobalFunction,fmt=fmtMock"
package clonefn
go generate mockcompose
將為您生成管道類,使您能夠編寫如下測試代碼:
package clonefn
import (
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var fmtMock *mockFmt = &mockFmt{}
func TestClonedFuncs(t *testing.T) {
assert := require.New(t)
// setup function mocks
fmtMock.On("Sprintf", mock.Anything, mock.Anything).Return("mocked Sprintf")
// inside functionThatUsesMultileGlobalFunctions: fmt.Sprintf is mocked
assert.True(functionThatUsesGlobalFunction_clone("format", "value") == "mocked Sprintf")
}
請查看此了解詳情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.