[英]Mocking a struct's method call in go tests
我正在寻找在测试中模拟结构的方法以提高代码覆盖率。 有一些关于这个的帖子,没有一个对我有用。 我可能完全弄错了。
main/file1.go
type application struct {
Name string
}
func (app *application) find() error {
// perform function logic
return nil
}
func main() {
app := &application{
Name: "Main Application",
}
err := app.find()
if err != nil {
fmt.Printf("Error in find call: %s\n", err)
}
}
我需要能够模拟find()
的测试并返回一个error
(我不想生成一个可能导致错误的测试用例,因为这不在我的控制之下,我不知道如何通过传递可接受的参数)。 我试图遵循这篇文章的第二个答案,但编译器不喜欢它。
main/file1_test.go
func Test_application_find(t *testing.T) {
tests := []struct {
name string
app *application
wantErr string
}{
{
name: "generate error",
app: &application{
Name: "Mock Application",
},
wantErr: true,
},
}
for _, tt := range tests {
mockCaller := tt.app.find // this works fine
tt.app.find = func() error { // this assignment errors out
return fmt.Errorf("Mock Error Message")
}
defer func() {
tt.app.find = mockCaller // this assignment errors out
}()
t.Run(tt.name, func(t *testing.T) {
if err := tt.app.find(); (err != nil) && (err.Error() != "Mock Error Message") {
t.Errorf("error = %s, wantErr %s", err.Error(), tt.wantErr)
}
}
}
}
我在这里做错了什么? 请建议。
有几种方法可以模拟一个方法。 他们都有适合的情况。
对于测试,您在原始结构之上创建一个新结构。
struct testApp struct{
application
}
现在teststruct
的行为方式几乎与app
相同,但您可以覆盖 find function:
func (app *testApp) find() error {
return errors.New("some error")
}
在测试中,您使用给定的适当app
初始化testApp
:
app := testApp{
application: &application{
Name: "Mock Application",
}
}
现在您可以在app
变量上编写测试。
请注意,这不适用于所有用例,因为组合不是 inheritance。 在原始application
上调用 function 不会在 testApp 中调用新的find
testApp
。
您还可以模拟整个应用程序结构/测试所需的部分。 如果您想测试另一个依赖于application
的结构,这主要是有意义的。
要测试的结构不应该直接使用application
,而是它需要的功能的接口。 (这可能意味着重构你的代码来做到这一点。)
然后使用模拟的find
function 创建一个模拟并将模拟传递给要测试的结构:
type app interface{
find() error
}
type mockApp struct{
Name string
}
(s *mockApp) find() error {
return errors.New("some error")
}
您还可以将find
function 设为结构字段。 然后您可以覆盖它以进行测试。 然而,这具有必须更改代码的缺点。
type application struct {
Name string
find func() error
}
编写一个创建者,以便能够以合理的方式初始化结构:
func newApplication() *application {
return &application{
Name: "Main Application",
find: func() error {
// perform function logic
return nil
}
}
}
现在您可以在测试中覆盖find
方法(实际上它现在是一个字段):
app := newApplication()
app.find = func() error {
return errors.New("some error")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.