对在其中启动 go 例程的函数进行单元测试

Posted

技术标签:

【中文标题】对在其中启动 go 例程的函数进行单元测试【英文标题】:Unit testing of a function that starts a go routine inside it 【发布时间】:2021-12-28 19:24:17 【问题描述】:

我的代码库大致如下

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时,我看到代码中有多个地方出现程序恐慌并给出invalid memory address or nil pointer dereference。我在调试模式下检查了代码,发现问题出在方法validateMyFunction 中的impl.GoRoutineWaitgroup.Add(1) 上,当我注释掉go validateMyFunction(a,b) 并再次运行测试时,日志中没有出现恐慌。那么我该如何解决这个问题呢?如何处理我们从内部启动 goroutine 的函数的单元测试(如本例所示)?

【问题讨论】:

您的WaitGroup 在示例代码中是nil。没有任何东西可以初始化它。 【参考方案1】:

您需要将值初始化为GoRoutineWaitgroup 字段。

ms := &ServiceGoRoutineWaitgroup: &sync.WaitGroup

或者从定义中删除指针

type Service struct 
    Repo                 repo 
    GoRoutineWaitgroup   sync.WaitGroup

我也没有在您的代码中看到等待等待组。像ms.GoRoutineWaitgroup.Wait() 这样的东西,你需要将 impl.GoRoutineWaitgroup.Add(1) 从validateMyFunction 移动到MyFunction,否则validateMyFunction 中的代码将不会被调用

【讨论】:

做到了。仍然遇到同样的问题。在做op := ms.MyFunction(test.input)之前我们需要做什么吗? 也许你在存储库的某个地方有错误。我删除了存储库,因为我没有其实现的详细信息,您需要将 impl.GoRoutineWaitgroup.Add(1) 移动到 MyFunction。我做了一个样本试试play.golang.org/p/PR-_u8uI-wY

以上是关于对在其中启动 go 例程的函数进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Go语言之单元测试

如何对在 Swift 中调用的私有方法进行单元测试

一文带你进行Go语言工程实践

一文带你进行Go语言工程实践

使用 axios、TypeScript 模板和异步函数对 VueJS 进行单元测试

Go-单元测试详解与代码