golang / mock

GoMock is a mocking framework for the Go programming language.
Apache License 2.0
9.29k stars 610 forks source link

Times() is not checking the exact number of function call. #596

Closed ryanking8215 closed 2 years ago

ryanking8215 commented 2 years ago

Actual behavior A clear and concise description of what the bug is. Times() checking is not correct, i.e, the mock function is called exact 1 time. But the testing will pass if mockObj.EXPECT().Func().Times(2), any number >=1 will all satisfy the checking.

Expected behavior A clear and concise description of what you expected to happen. Testing should be failed if pass the number which is not the exact number of function call by using Times()

To Reproduce Steps to reproduce the behavior

interface and caller definition

//go:generate mockgen -destination=./killer_mock.go -package=gomock_demo . Killer
type Killer interface {
    Kill()
}

func MustKill(killer Killer, times int) {
    for i := 0; i < times; i++ {
        killer.Kill()
    }
}

testing code

import (
    "testing"

    "github.com/golang/mock/gomock"
    . "github.com/onsi/ginkgo"
    . "github.com/onsi/gomega"
)

func TestKiller(t *testing.T) {
    RegisterFailHandler(Fail)
    RunSpecs(t, "Kill Suite")
}

var _ = Describe("killer", func() {
    var (
        t        = GinkgoT()
        mockCtrl = gomock.NewController(t)
        killer   = NewMockKiller(mockCtrl)
    )

    Context("MustKill", func() {
        It("1", func() {
            killer.EXPECT().Kill().Times(2) // it should be failed here because of '2'.
            MustKill(killer, 1)
        })
    })
})

Additional Information

Triage Notes for the Maintainers I am not sure it is a bug or it is designed on purpose. But the behave of Times() checking is counterintuitive.

I read the source code, the method Caller.satisfied() is not invoked by caller instance itself, it is invoked by caller's preReq list.

ryanking8215 commented 2 years ago

Sorry, it is not a bug that I found the issue is the misusage of Ginkgo.

GinkgoT() is return a testing proxy instance which implement an dummy Cleanup function, it is not the *testing.T instance passed to RunSpecs.

Solution:

  1. pass *testing.T instance to gomock.NewController or
  2. Invoke mockCtrl.Finish() explicitly.