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)
我是 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)