对在其中启动 go 例程的函数进行单元测试
Unit testing of a function that starts a go routine inside it
我有一个代码库,大致如下
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")
}
我写了类似这样的单元测试。
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.
所有测试均成功。但是当执行命令 go test -v
时,我看到代码中有多个地方程序 panic 并给出了 invalid memory address or nil pointer dereference
。我在调试模式下检查了代码,意识到问题出在方法 validateMyFunction
中的 impl.GoRoutineWaitgroup.Add(1)
并且当我再次注释掉 go validateMyFunction(a,b)
和 运行 测试时,没有恐慌日志。那么我该如何解决这个问题呢?如何处理我们从内部启动 goroutine 的函数的单元测试(如本例)?
您需要将值初始化为 GoRoutineWaitgroup
字段。
ms := &Service{GoRoutineWaitgroup: &sync.WaitGroup{}}
或从定义中删除指针
type Service struct {
Repo repo
GoRoutineWaitgroup sync.WaitGroup
}
此外,我在您的代码中没有看到等待组。像 ms.GoRoutineWaitgroup.Wait()
这样的东西,你需要将 impl.GoRoutineWaitgroup.Add(1) 从 validateMyFunction
移动到 MyFunction
否则 validateMyFunction
中的代码将不会被调用
我有一个代码库,大致如下
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")
}
我写了类似这样的单元测试。
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.
所有测试均成功。但是当执行命令 go test -v
时,我看到代码中有多个地方程序 panic 并给出了 invalid memory address or nil pointer dereference
。我在调试模式下检查了代码,意识到问题出在方法 validateMyFunction
中的 impl.GoRoutineWaitgroup.Add(1)
并且当我再次注释掉 go validateMyFunction(a,b)
和 运行 测试时,没有恐慌日志。那么我该如何解决这个问题呢?如何处理我们从内部启动 goroutine 的函数的单元测试(如本例)?
您需要将值初始化为 GoRoutineWaitgroup
字段。
ms := &Service{GoRoutineWaitgroup: &sync.WaitGroup{}}
或从定义中删除指针
type Service struct {
Repo repo
GoRoutineWaitgroup sync.WaitGroup
}
此外,我在您的代码中没有看到等待组。像 ms.GoRoutineWaitgroup.Wait()
这样的东西,你需要将 impl.GoRoutineWaitgroup.Add(1) 从 validateMyFunction
移动到 MyFunction
否则 validateMyFunction
中的代码将不会被调用