英文:
Unit testing of a function that starts a go routine inside it
问题
我有一个大致如下的代码库:
type Service struct {
Repo repo // 包含 FunctionOne 和 FunctionTwo 的接口
GoRoutineWaitgroup *sync.WaitGroup
}
func (impl *Service) MyFunction(s string) bool {
a := impl.Repo.FunctionOne()
b := impl.Repo.FunctionTwo()
fmt.Println("执行了 Function One 和 Function two")
go impl.validateMyFunction(a,b)
return true
}
func (impl *Service) validateMyFunction(a string,b string) {
defer helpers.PanicHandler()
impl.GoRoutineWaitgroup.Add(1)
defer impl.GoRoutineWaitgroup.Done()
fmt.Println("验证了 a 和 b")
}
我编写了类似以下的单元测试:
func TestMyFunction(t *testing.T) {
ms := &Service{}
test := []struct{
input string
output bool
case string
}{
{"a", true, "sample"}
}
}
for _, test := range tests {
t.Run(test.case, func(t *testing.T) {
mockRepo := new(mockrepo.Repo) // mockRepo 包含使用 mockery 生成的原始 repo 层方法的模拟方法,用于测试目的
mockRepo.On("FunctionOne")
mockRepo.On("FunctionTwo")
ms.Repo = mockRepo
op := ms.MyFunction(test.input)
assert.Equal(t, test.Output, op)
})
}
} // 请记住,这不是我的实际代码,只是一个基本结构。
所有的测试都成功了。但是当执行命令 go test -v
时,我在代码中看到了多个程序崩溃并显示 invalid memory address or nil pointer dereference
。我在调试模式下检查了代码,并意识到问题出在 validateMyFunction
方法中的 impl.GoRoutineWaitgroup.Add(1)
上,当我注释掉 go validateMyFunction(a,b)
并再次运行测试时,日志中就没有崩溃了。那么我该如何解决这个问题?如何处理从内部启动 goroutine 的函数的单元测试(就像这个案例中一样)?
英文:
I have a codebase that is roughly as follows
type Service struct {
Repo repo // An interface that contains both FunctionOne and FunctionTwo
GoRoutineWaitgroup *sync.WaitGroup
}
func (impl *Service) MyFunction(s string) bool {
a := impl.Repo.FunctionOne()
b := impl.Repo.FunctionTwo()
fmt.Println("Executed Function One and Function two")
go impl.validateMyFunction(a,b)
return true
}
func (impl *Service) validateMyFunction(a string,b string) {
defer helpers.PanicHandler()
impl.GoRoutineWaitgroup.Add(1)
defer impl.GoRoutineWaitgroup.Done()
fmt.Println("a and b are validated")
}
And I wrote unit tests as something similar to this.
func TestMyFunction(t *testing.T) {
ms := &Service{}
test := []struct{
input string
output bool
case string
}{
{"a", true, sample}
}
}
for _, test := range tests {
t.Run(test.case, func(t *testing.T) {
mockRepo := new(mockrepo.Repo) // mockRepo contains mocks of original repo layer methods generated using mockery for testing purposes
mockRepo.On("FunctionOne")
mockRepo.On("FunctionTwo")
ms.Repo = mockRepo
op := ms.MyFunction(test.input)
assert.Equal(t, test.Output, op)
})
}
} // Please keep in mind that this is not my actual code, but just a basic structure.
All tests are successful. But when executing the command go test -v
, I saw multiple places in the code where the program panicked and gave invalid memory address or nil pointer dereference
. I checked the code in debug mode and realized that the issue is with impl.GoRoutineWaitgroup.Add(1)
in method validateMyFunction
and when I commented out go validateMyFunction(a,b)
and ran tests again, there were no panics in the logs. So How do I solve this issue? How to handle unit tests of functions where we start a goroutine from inside ( as in this case )?
答案1
得分: 0
你需要对GoRoutineWaitgroup
字段进行初始化。
ms := &Service{GoRoutineWaitgroup: &sync.WaitGroup{}}
或者从定义中移除指针。
type Service struct {
Repo repo
GoRoutineWaitgroup sync.WaitGroup
}
此外,我没有在你的代码中看到等待 Wait Group 的部分。类似于 ms.GoRoutineWaitgroup.Wait()
,你需要将 impl.GoRoutineWaitgroup.Add(1)
从 validateMyFunction
移动到 MyFunction
中,否则 validateMyFunction
中的代码将不会被调用。
英文:
You need initialize value to GoRoutineWaitgroup
field.
ms := &Service{GoRoutineWaitgroup: &sync.WaitGroup{}}
Or remove pointer from definition
type Service struct {
Repo repo
GoRoutineWaitgroup sync.WaitGroup
}
Also I do not see waiting for Wait Group in your code. Something like ms.GoRoutineWaitgroup.Wait()
and you need to move impl.GoRoutineWaitgroup.Add(1) to MyFunction
from validateMyFunction
otherwise the code in validateMyFunction
will not be called
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论