一个函数内部启动一个go routine的单元测试。

huangapple go评论125阅读模式
英文:

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

huangapple
  • 本文由 发表于 2021年11月18日 03:59:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/70010794.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定