stretchr / testify

A toolkit with common assertions and mocks that plays nicely with the standard library
MIT License
23.11k stars 1.58k forks source link

mock returns panic when API uses context #519

Open santoshaitha opened 6 years ago

santoshaitha commented 6 years ago

go test command returns below panic when we try to use mocks.On: Does testify/mock support context as a parameter.

it reports it is getting type as context.emptyContext

mockery generated API as below:

// SetSchema provides a mock function with given fields: ctx, in func (_m MockUtils) SetSchema(ctx context.Context, in models.Schema) (*models.Schema, error) { ret := _m.Called(ctx, in)

var r0 *models.Schema
if rf, ok := ret.Get(0).(func(context.Context, *models.Schema) *models.Schema); ok {
    r0 = rf(ctx, in)
} else {
    if ret.Get(0) != nil {
        r0 = ret.Get(0).(*models.Schema)
    }
}

var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *models.Schema) error); ok {
    r1 = rf(ctx, in)
} else {
    r1 = ret.Error(1)
}

return r0, r1

}

I am using mocks.On as below:

func TestUtils(){ // ..... /// mclient.On("SetSchema", mock.AnythingOfType("context.Context"), mock.AnythingOfType("*models.Schema")).Return(schemaData) ctx := context.Background() s, _ := mockutils.SetSchema(ctx, schemaData) }

i see below panic from mock package. mock: Unexpected Method Call

SetSchema(context.emptyCtx,models.Schema) *0: (context.emptyCtx)(0xc420011058)** 1: &models.Schema{ID:"", SchemaID:""}

The closest call I have is:

SetSchema(mock.AnythingOfTypeArgument,mock.AnythingOfTypeArgument) 0: "context.Context" 1: "*models.Schema"

goroutine 11 [running]: testing.tRunner.func1(0xc4200740d0) /usr/local/go/src/testing/testing.go:622 +0x29d panic(0x14ba5a0, 0xc4204c32b0) /usr/local/go/src/runtime/panic.go:489 +0x2cf vendor/github.com/stretchr/testify/mock.(Mock).MethodCalled(0xc4202e24c0, 0x17ff0d6, 0x9, 0xc4204c5080, 0x2, 0x2, 0x7, 0x2, 0xc42003c960) /Users/saaitha/Documents/vendor/github.com/stretchr/testify/mock/mock.go:311 +0x6db vendor/github.com/stretchr/testify/mock.(Mock).Called(0xc4202e24c0, 0xc4204c5080, 0x2, 0x2, 0x1, 0xc42003c9d8, 0x11eae6a)

jamesonjlee commented 6 years ago

have you tried *context.emptyCtx or context.emptyCtx or AnythingOfType(context.Background())?

I had a similar issue that was solved by passing in name of the context type that I expect to be passed.

example of context.Background() != context.Context when reflected. https://play.golang.org/p/w9vIzEUZAg

santoshaitha commented 6 years ago

Yes i tried all these types got similar kind of error each time

santoshaitha commented 6 years ago

It works with AnythingOfType(*context.emptyCtx). But as context.Context is of type interface, isn't AnythingOfType should accept context.Context also?

ernesto-jimenez commented 6 years ago

@santoshaitha yes, it should allow for interfaces.

We would need to change the reflection checks inside AnythingOfType to accept an interface and check whether the argument is assignable to that interface.

santoshaitha commented 6 years ago

Thanks Hope it will be fixed in future commits.

evan2645 commented 6 years ago

@santoshaitha this is under go 1.9.2? Can you reproduce under go 1.8.3?

evan2645 commented 6 years ago

I have bumped into something like this after upgrading to go 1.9.2 and updating my project dependencies. I don't fully understand the nature of what's described here, but my failure mode seems similar.

I'm running into panics when trying to return interfaces from EXPECT calls, i.e. EXPECT().Foo().Return(interface_conforming_type_here). Using testify's current master (87b1dfb5b2fa649f52695dd9eae19abe404a4308), I've isolated the introduction of the panic to this change in gomock: https://github.com/golang/mock/commit/0ee1ab233dea3381025c1dadac936b2be32293cc

This very well may be a different problem than the one described here... if so just let me know, I'm happy to post it elsewhere. For now, I'll be pinning gomock version to the commit just prior.

EDIT>> I am using testify/suite. I didn't see any issues or PRs open against gomock and this change has been around for some time, so it's possible it has nothing to do with testify at all... hopefully someone more knowledgable than myself can chime in here :)

santoshaitha commented 6 years ago

Yes it is different problem than described in this defect. The issue in this defect is with AnythingOfType doesn't accept interface type but where as your issue related to Return() API.

ghost commented 3 years ago

Have you solved your issue? I believe that I've encountered this and that you can work around it by using mock.MatchedBy(func(ctx context.Context) bool { return true}) instead. This isn't the prettiest thing but it is easy to create a variable once and reuse it.

georgysavva commented 3 years ago

Hi. Is there any update on adding the ability to write mock.AnythingOfType("context.Context")?

rana commented 3 years ago

mock.MatchedBy(func(ctx context.Context) bool { return true})

This solved it for the time being

nishanths commented 3 years ago

Is it possible to use MatchedBy if my method takes multiple arguments? e.g.

func (o *Obj) Create(ctx context.Context, id string) error

The documentation requires the argument function passed to MatchedBy to have exactly one parameter. Otherwise, as documented, it panics.

nishanths commented 3 years ago

I was able to resolve my earlier question using AnythingOfType.

go version go1.16 darwin/amd64
github.com/stretchr/testify v1.7.0
obj.
    On("Create", mock.AnythingOfType(fmt.Sprintf("%T", context.Background())), "xyz").
    Return(nil).
    Times(1)

This also seems like a possible solution to @georgysavva's question above.

Hi. Is there any update on adding the ability to write mock.AnythingOfType("context.Context")?

nishanths commented 3 years ago

Is it possible to use MatchedBy if my method takes multiple arguments?

On further working this package, I think I would have had to do:

On("Create", 
    mock.MatchedBy(func(_ context.Context) bool { return true }), 
    mock.MatchedBy(func(s string) bool { ... }), 
)

in order to suit:

func (o *Obj) Create(ctx context.Context, id string) error
yuseferi commented 1 year ago

mock.Anything or mock.MatchedBy(func(ctx context.Context) bool { return true}} works