I’m working on my pet project application that involves batching data requests to an external service. I’ve implemented a method to handle this batching, and I’ve also written unit tests to ensure everything works as expected. However, I’m encountering an issue with one of my test cases where the handler returns an empty slice.
Here’s the implementation of the Client and the GetItemsInfo method:
const (
batchSize = 100
)
type Client struct {
client generated.Client
}
type ItemInfo struct {
ID int64
}
func (c *Client) GetItemsInfo(ctx context.Context, ids []int64) ([]ItemInfo, error) {
itemsInfo := NewItemsInfoData()
eg, ctx := errgroup.WithContext(ctx)
for offset := 0; offset < len(ids); offset += batchSize {
batchItemIDs := ids[offset:math.Min(offset+batchSize, len(ids))]
batch := batchItemIDs
eg.Go(func() error {
resp, err := c.client.GetItemsInfo(ctx, &generated.GetItemsInfoIn{ItemIDs: batch})
if err != nil {
return err
}
itemsInfo.Store(resp.Items)
return nil
})
}
if err := eg.Wait(); err != nil {
return nil, fmt.Errorf("get items info: %w", err)
}
return itemsInfo.GetData(), nil
}
func NewItemsInfoData() *ItemsInfoData {
return &ItemsInfoData{}
}
type ItemsInfoData struct {
items []ItemInfo
mx sync.Mutex
}
func (d *ItemsInfoData) Store(items []ItemInfo) {
d.mx.Lock()
defer d.mx.Unlock()
d.items = append(d.items, items...)
}
func (d *ItemsInfoData) GetData() []ItemInfo {
d.mx.Lock()
defer d.mx.Unlock()
return d.items
}
And here is the corresponding unit test:
func TestClient_GetItemsInfo(t *testing.T) {
item1 := ItemInfo{ID: 12}
item2 := ItemInfo{ID: 5}
item3 := ItemInfo{ID: 11}
type fields struct {
client MockClient
}
type args struct {
itemIDs []int64
}
tests := []struct {
name string
fields func(ctrl *gomock.Controller) fields
args args
want []ItemInfo
wantErr bool
}{
{
name: "multiple_batches",
fields: func(ctrl *gomock.Controller) fields {
mockClient := mocks.NewMockClient(ctrl)
mockClient.EXPECT().GetItemsInfo(gomock.Any(), &generated.GetItemsInfoIn{ItemIDs: []int64{12}}).
Return(&generated.GetItemsInfoOut{Items: []ItemInfo{item1}}, nil).Times(1)
mockClient.EXPECT().GetItemsInfo(gomock.Any(), &generated.GetItemsInfoIn{ItemIDs: []int64{5}}).
Return(&generated.GetItemsInfoOut{Items: []ItemInfo{item2}}, nil).Times(1)
mockClient.EXPECT().GetItemsInfo(gomock.Any(), &generated.GetItemsInfoIn{ItemIDs: []int64{11}}).
Return(&generated.GetItemsInfoOut{Items: []ItemInfo{item3}}, nil).Times(1)
return fields{
client: mockClient,
}
},
args: args{
itemIDs: []int64{12, 5, 11},
},
want: []ItemInfo{item1, item2, item3},
wantErr: false,
},
{
name: "one_batch",
fields: func(ctrl *gomock.Controller) fields {
mockClient := mocks.NewMockClient(ctrl)
mockClient.EXPECT().GetItemsInfo(gomock.Any(), &generated.GetItemsInfoIn{ItemIDs: []int64{12, 5, 11}}).
Return(&generated.GetItemsInfoOut{Items: []ItemInfo{item1, item2, item3}}, nil).Times(1)
return fields{
client: mockClient,
}
},
args: args{
itemIDs: []int64{12, 5, 11},
},
want: []ItemInfo{item1, item2, item3},
wantErr: false,
},
{
name: "error_handling",
fields: func(ctrl *gomock.Controller) fields {
mockClient := mocks.NewMockClient(ctrl)
mockClient.EXPECT().GetItemsInfo(gomock.Any(), gomock.Any()).
Return(nil, errors.New("some error")).Times(1)
return fields{
client: mockClient,
}
},
args: args{
itemIDs: []int64{12, 5},
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
f := tt.fields(ctrl)
c := &Client{client: f.client}
got, err := c.GetItemsInfo(context.Background(), tt.args.itemIDs)
if (err != nil) != tt.wantErr {
t.Errorf("GetItemsInfo() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetItemsInfo() got = %v, want %v", got, tt.want)
}
})
}
}
But in the “multiple_batches” test case, the handler returns an empty slice, even though I have configured my mock to return the expected values when a request is made.
Why is the handler returning an empty slice, and how can I resolve this issue? Your insights or suggestions would be greatly appreciated!