Golang mock context panic
Asked Answered
A

1

6

So I'm making unit test in golang using mockery and testify

The test code goes like this:

const bufSize = 1024 * 1024

var lis *bufconn.Listener

var mockAccountService = &mocks.AccountService{}

func init() {
    lis = bufconn.Listen(bufSize)
    s := grpc.NewServer()
    RegisterAccountManagementHandlerServer(s, &server{mockAccountService})
    go func() {
        if err := s.Serve(lis); err != nil {
            log.Fatalf("Server exited with error: %v", err)
        }
    }()
}

func bufDialer(context.Context, string) (net.Conn, error) {
    return lis.Dial()
}

func TestSayHello(t *testing.T) {

    var a uint64 = 1

    ctx := context.Background()

    conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
    if err != nil {
        t.Fatalf("Failed to dial bufnet: %v", err)
    }
    defer conn.Close()
    client := NewAccountManagementHandlerClient(conn)

    mockAccountService.On("GetSavingAccount", context.Background(), a, a, "Hello", 1).Return(&models.SavingAccount{
        CustomerID:      1,
        ID:              1,
        CardNo:          "Hello",
        SavingProductID: 1,
        Balance:         0,
        Status:          1,
    })

    resp, err := client.GetSavingAccount(ctx, &GetSavingAccountDataRequest{
        Id:              1,
        CustomerId:      1,
        CardNo:          "Hello",
        SavingProductId: 1,
    })

    if err != nil {
        t.Fatalf("SayHello failed: %v", err)
    }
    fmt.Printf("Response: %+v", resp)
    // Test for output here.

But I get the error like this:


panic: 

mock: Unexpected Method Call
-----------------------------

GetSavingAccount(*context.valueCtx,uint64,uint64,string,int64)
                0: &context.valueCtx{Context:(*context.valueCtx)(0xc000115260), key:grpc.streamKey{}, val:(*transport.Stream)(0xc0004a2200)}
                1: 0x1
                2: 0x1
                3: "Hello"
                4: 1

The closest call I have is: 

GetSavingAccount(mock.AnythingOfTypeArgument,uint64,uint64,string,int)
                0: "&context.ValueCtx"
                1: 0x1
                2: 0x1
                3: "Hello"
                4: 1

What value should I pass to mock context.Background()?

I tried mock.AnythingOfType("&context.emptyCtx"), mock.Anything, doesn't work

Thank you

EDIT:

I tried

mockAccountService.On("GetSavingAccount", context.Background(), a, a, "Hello", 1).Return(...})

And get:

GetSavingAccount(*context.valueCtx,uint64,uint64,string,int64)
                0: &context.valueCtx{Context:(*context.valueCtx)(0xc000021290), key:grpc.streamKey{}, val:(*transport.Stream)(0xc000522100)}
                ...
The closest call I have is: 

GetSavingAccount(*context.emptyCtx,uint64,uint64,string,int)
                0: (*context.emptyCtx)(0xc00002a080)
                ...

The method definition for GetSavingAccount method is:

func (a *accountService) GetSavingAccount(ctx context.Context, customerID, id uint64, cardNo string, savingProductId int64) (*models.SavingAccount, error)

Antabuse answered 2/7, 2020 at 11:52 Comment(5)
How do you inject "mockAccountService" to be used by client?Probst
Add please, add the function definition for GetSavingAccount method, to see parameters and return types. And, mock.Anything works fine for context, here should be another problem, not with context.Probst
You don't mock context.Background(). Just use context.Background(). Why do you think you want a mock?Kindergartner
@Flimzy I tried your advice, result is in question that I editAntabuse
@VasileRazdalovschi I edit my question, adding function Definition for GetSavingAccount method and complete test fileAntabuse
P
9

So, you have method:

GetSavingAccount(*context.Context,uint64,uint64,string,int64)

And you have mocked:

GetSavingAccount(*context.Context,uint64,uint64,string,int)

You have difference in the last parameter, your problem is int64 and int, so you need:

mockAccountService.On("GetSavingAccount", mock.Anything, a, a, "Hello", int64(1)).Return(...})

For context parameters always use mock.Anything, it is more easier than to mock context. Be careful with int/int64/int32 and other types, also for pointer/struct parameters.

Probst answered 2/7, 2020 at 12:46 Comment(3)
@DimasAnggaSaputra Also, if you don't like mock.Anything, you can do: ctx := context.Background() service.Mock("method", ctx,...) client.Do(ctx, ...) And you will skip this mock.Anything, but it is a little ugly, depends on your taste :)Probst
What if that changes to context.TODO() or something other than the background context? It's not a very good test to only test the background contextIdentify
@Identify it depends on your test and why are you passing context. In this test, you expect to see what exactly is passed as parameters of the function and if you expect to have context.TODO(), then feel free to expect it, but more probably, you will expect to test other parameters and context just to ignore. If you pass something in context and want to test that it is passed, then you might revisit how you test that function and maybe mock is not the best way.Probst

© 2022 - 2024 — McMap. All rights reserved.