Go goroutine 测试失败预期调用次数

Go goroutine test failing Expected number of calls

我是 Go 的新手。我正在尝试在我的 Go 例程中测试函数调用,但它失败并显示错误消息

Expected number of calls (8) does not match the actual number of calls (0).

我的测试代码如下:

package executor

import (
    "testing"
  "sync"
    "github.com/stretchr/testify/mock"
)

type MockExecutor struct {
    mock.Mock
  wg sync.WaitGroup
}

func (m *MockExecutor) Execute() {
  defer m.wg.Done()
}

func TestScheduleWorksAsExpected(t *testing.T) {

    scheduler := GetScheduler()
    executor := &MockExecutor{}
    scheduler.AddExecutor(executor)

    // Mock exptectations
    executor.On("Execute").Return()
    

    // Function Call
  executor.wg.Add(8)
    scheduler.Schedule(2, 1, 4)
  executor.wg.Wait()

  executor.AssertNumberOfCalls(t, "Execute", 8)

}

我的申请代码是:

package executor

import (
    "sync"
    "time"
)

type Scheduler interface {
    Schedule(repeatRuns uint16, coolDown uint8, parallelRuns uint64)
    AddExecutor(executor Executor)
}

type RepeatScheduler struct {
    executor  Executor
    waitGroup sync.WaitGroup
}

func GetScheduler() Scheduler {
    return &RepeatScheduler{}
}

func (r *RepeatScheduler) singleRun() {
    defer r.waitGroup.Done()
    r.executor.Execute()
}

func (r *RepeatScheduler) AddExecutor(executor Executor) {
    r.executor = executor
}

func (r *RepeatScheduler) repeatRuns(parallelRuns uint64) {
    for count := 0; count < int(parallelRuns); count += 1 {
        r.waitGroup.Add(1)
        go r.singleRun()
    }

    r.waitGroup.Wait()
}

func (r *RepeatScheduler) Schedule(repeatRuns uint16, coolDown uint8, parallelRuns uint64) {

    for repeats := 0; repeats < int(repeatRuns); repeats += 1 {
        r.repeatRuns(parallelRuns)
        time.Sleep(time.Duration(coolDown))
    }

}

你能指出我这里可能做错了什么吗?我正在使用 Go 1.16.3。当我调试我的代码时,我可以看到正在调用 Execute() 函数,但 testify 无法注册函数调用

您需要调用 Called() 以便 mock.Mock 记录 Execute() 已被调用的事实。由于您不担心参数或 return 值,因此以下应该可以解决您的问题:

func (m *MockExecutor) Execute() {
    defer m.wg.Done()
    m.Called()
}

但是我注意到您的测试当前编写的方式可能无法完成您想要的。这是因为:

  • 您在调用 executor.AssertNumberOfCalls 之前调用 executor.wg.Wait()(它将等待函数被调用预期的次数),因此如果 Execute() 未完成,您的测试将永远不会完成至少调用预期次数(wg.Wait() 将永远阻塞)。
  • m.Called() 被调用预期次数后存在竞争条件(如果 executor 仍然是 运行 executor.AssertNumberOfCalls 和之间存在竞争下一个 m.Called())。如果 wg.Done() 确实被调用了额外的时间,你会感到恐慌(我想你可以认为是失败!)但我可能会稍微简化测试:
scheduler.Schedule(2, 1, 4)
time.Sleep(time.Millisecond) // Wait long enough that all executions are guaranteed to have completed (should be quick as Schedule waits for go routines to end)
executor.AssertNumberOfCalls(t, "Execute", 8)