【问题标题】:Go goroutine test failing Expected number of callsGo goroutine 测试失败预期调用次数
【发布时间】:2021-05-06 00:25:23
【问题描述】:

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

预期调用次数 (8) 与实际调用次数不符 (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 无法注册函数调用

【问题讨论】:

    标签: go testify


    【解决方案1】:

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

    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)
    

    【讨论】:

    • 感谢您的回复。我看到m.Called() 如何帮助我的用例。另外,理想情况下,如果我的 Wait() 可以超时,那会有所帮助,但我会接受这个。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 2017-07-15
    • 1970-01-01
    • 2015-11-09
    • 2021-09-15
    • 1970-01-01
    相关资源
    最近更新 更多