github.com/willyham/dosa@v2.3.1-0.20171024181418-1e446d37ee71+incompatible/examples/testing/README.md (about) 1 # Examples: Testing 2 3 The example here demonstrates how to write tests for code that uses the DOSA 4 client. For now, we are suggesting the use of a mock client that we have 5 generated using [MockGen](https://github.com/golang/mock). It's available 6 as `(github.com/uber-go/dosa/mocks).MockClient`. 7 8 ## `MockClient` Usage 9 10 Given an entity defined as: 11 12 type User struct { 13 dosa.Entity `dosa:"primaryKey=UUID"` 14 UUID dosa.UUID 15 Name string 16 Email string 17 CreatedOn time.Time 18 } 19 20 And a method that operates on that entity called `GetUser`: 21 22 type Datastore struct { 23 client dosa.Client 24 } 25 26 func (d *Datastore) GetUser(ctx context.Context, uuid dosa.UUID) (*User, error) { 27 user := &User{uuid: uuid} 28 readCtx, readCancel := context.WithTimeout(ctx, 1 * time.Second) 29 if err := d.client.Read(readCts 30 } 31 32 The `client` behavior can then be mocked using `MockClient`: 33 34 package datastore_test 35 36 import ( 37 "github.com/golang/mock/gomock" 38 "github.com/stretchr/testify/assert" 39 40 "github.com/uber-go/dosa" 41 examples "github.com/uber-go/dosa/examples/testing" 42 "github.com/uber-go/dosa/mocks" 43 ) 44 45 func TestGetUser(t *testing.T) { 46 ctrl := gomock.NewController(t) 47 defer ctrl.Finish() 48 49 // mock error from `Read` call 50 c1 := mocks.NewMockClient(ctrl) 51 c1.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1) 52 c1.EXPECT().Read(gomock.Any(), nil, user).Return(errors.New("Read Error")).Times(1) 53 ds1, _ := examples.NewDatastore(c1) 54 55 u1, err1 := ds1.GetUser(ctx, uuid) 56 assert.Error(t, err1) 57 assert.Nil(t, u1) 58 59 // happy path 60 c2 := mocks.NewMockClient(ctrl) 61 c2.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1) 62 c2.EXPECT().Read(gomock.Any(), nil, user).Return(nil).Times(1) 63 ds2, _ := examples.NewDatastore(c2) 64 65 u2, err2 := ds2.GetUser(ctx, uuid) 66 assert.NoError(t, err2) 67 assert.Equal(t, u2, user) 68 } 69 70 A complete, runnable example of this can be found in our [testing examples package](https://github.com/uber-go/dosa/tree/master/examples/testing). 71 72 ## `EqRangeOp` and `EqScanOp` 73 74 In addition to the `MockClient`, dosa provides two useful `gomock.Matcher`s. `EqRangeOp` allows you to verify 75 that an expected call to `Range` is made with a specific `RangeOp`. `EqScanOp` does the same thing, except for 76 the `Scan` function. For instance, assume we have the following entity: 77 78 ```Go 79 type MenuItem struct { 80 dosa.Entity `dosa:"primaryKey=((MenuUUID), MenuItemUUID)"` 81 MenuUUID dosa.UUID 82 MenuItemUUID dosa.UUID 83 Name string 84 Description string 85 } 86 ``` 87 88 Let's also assume we add the following receiver function to our `DataStore` struct: 89 ```Go 90 func (d *Datastore) GetMenu(ctx context.Context, menuUUID dosa.UUID) ([]*MenuItem, error) { 91 op := dosa.NewRangeOp(&MenuItem{}).Eq("MenuUUID", menuUUID).Limit(50) 92 rangeCtx, rangeCancelFn := context.WithTimeout(ctx, 1*time.Second) 93 defer rangeCancelFn() 94 95 objs, _, err := d.client.Range(rangeCtx, op) 96 if err != nil { 97 return nil, err 98 } 99 100 menuItems := make([]*MenuItem, len(objs)) 101 for i, obj := range objs { 102 menuItems[i] = obj.(*MenuItem) 103 } 104 return menuItems, nil 105 } 106 ``` 107 108 In our tests, we could verify that a particular list of `MenuItem` entities were queried for using the `EqRangeOp` 109 like so: 110 ```Go 111 func TestGetMenu(t *testing.T) { 112 ctrl := gomock.NewController(t) 113 defer ctrl.Finish() 114 115 expectedOp := dosa.NewRangeOp(&examples.MenuItem{}).Eq("MenuUUID", menuUUID).Limit(50) 116 117 // mock error from Range call 118 c1 := mocks.NewMockClient(ctrl) 119 c1.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1) 120 c1.EXPECT().Range(gomock.Any(), dosa.EqRangeOp(expectedOp)).Return(nil, "", errors.New("Range Error")).Times(1) 121 ds1, _ := examples.NewDatastore(c1) 122 123 m1, err1 := ds1.GetMenu(ctx, menuUUID) 124 assert.Error(t, err1) 125 assert.Nil(t, m1) 126 127 // happy path 128 c2 := mocks.NewMockClient(ctrl) 129 c2.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1) 130 c2.EXPECT().Range(gomock.Any(), dosa.EqRangeOp(expectedOp)).Return(objMenu, "", nil).Times(1) 131 ds2, _ := examples.NewDatastore(c2) 132 133 m2, err2 := ds2.GetMenu(ctx, menuUUID) 134 assert.NoError(t, err2) 135 assert.Equal(t, menu, m2) 136 } 137 ```