testingexamples

package
v2.3.0+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2017 License: MIT Imports: 3 Imported by: 0

README

Examples: Testing

The example here demonstrates how to write tests for code that uses the DOSA client. For now, we are suggesting the use of a mock client that we have generated using MockGen. It's available as (github.com/uber-go/dosa/mocks).MockClient.

MockClient Usage

Given an entity defined as:

type User struct {
    dosa.Entity `dosa:"primaryKey=UUID"`
    UUID        dosa.UUID
    Name        string
    Email       string
    CreatedOn   time.Time
}

And a method that operates on that entity called GetUser:

type Datastore struct {
    client dosa.Client
}

func (d *Datastore) GetUser(ctx context.Context, uuid dosa.UUID) (*User, error) {
    user := &User{uuid: uuid}
    readCtx, readCancel := context.WithTimeout(ctx, 1 * time.Second)
    if err := d.client.Read(readCts
}

The client behavior can then be mocked using MockClient:

package datastore_test

import (
    "github.com/golang/mock/gomock"
    "github.com/stretchr/testify/assert"

    "github.com/uber-go/dosa"
    examples "github.com/uber-go/dosa/examples/testing"
    "github.com/uber-go/dosa/mocks"
)

func TestGetUser(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    // mock error from `Read` call
    c1 := mocks.NewMockClient(ctrl)
    c1.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c1.EXPECT().Read(gomock.Any(), nil, user).Return(errors.New("Read Error")).Times(1)
    ds1, _ := examples.NewDatastore(c1)

    u1, err1 := ds1.GetUser(ctx, uuid)
    assert.Error(t, err1)
    assert.Nil(t, u1)

    // happy path
    c2 := mocks.NewMockClient(ctrl)
    c2.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c2.EXPECT().Read(gomock.Any(), nil, user).Return(nil).Times(1)
    ds2, _ := examples.NewDatastore(c2)

    u2, err2 := ds2.GetUser(ctx, uuid)
    assert.NoError(t, err2)
    assert.Equal(t, u2, user)
}

A complete, runnable example of this can be found in our testing examples package.

EqRangeOp and EqScanOp

In addition to the MockClient, dosa provides two useful gomock.Matchers. EqRangeOp allows you to verify that an expected call to Range is made with a specific RangeOp. EqScanOp does the same thing, except for the Scan function. For instance, assume we have the following entity:

type MenuItem struct {
    dosa.Entity `dosa:"primaryKey=((MenuUUID), MenuItemUUID)"`
    MenuUUID     dosa.UUID
    MenuItemUUID dosa.UUID
    Name         string
    Description  string
}

Let's also assume we add the following receiver function to our DataStore struct:

func (d *Datastore) GetMenu(ctx context.Context, menuUUID dosa.UUID) ([]*MenuItem, error) {
	op := dosa.NewRangeOp(&MenuItem{}).Eq("MenuUUID", menuUUID).Limit(50)
	rangeCtx, rangeCancelFn := context.WithTimeout(ctx, 1*time.Second)
	defer rangeCancelFn()

	objs, _, err := d.client.Range(rangeCtx, op)
	if err != nil {
		return nil, err
	}

	menuItems := make([]*MenuItem, len(objs))
	for i, obj := range objs {
		menuItems[i] = obj.(*MenuItem)
	}
	return menuItems, nil
}

In our tests, we could verify that a particular list of MenuItem entities were queried for using the EqRangeOp like so:

func TestGetMenu(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    expectedOp := dosa.NewRangeOp(&examples.MenuItem{}).Eq("MenuUUID", menuUUID).Limit(50)

    // mock error from Range call
    c1 := mocks.NewMockClient(ctrl)
    c1.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c1.EXPECT().Range(gomock.Any(), dosa.EqRangeOp(expectedOp)).Return(nil, "", errors.New("Range Error")).Times(1)
    ds1, _ := examples.NewDatastore(c1)

    m1, err1 := ds1.GetMenu(ctx, menuUUID)
    assert.Error(t, err1)
    assert.Nil(t, m1)

    // happy path
    c2 := mocks.NewMockClient(ctrl)
    c2.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c2.EXPECT().Range(gomock.Any(), dosa.EqRangeOp(expectedOp)).Return(objMenu, "", nil).Times(1)
    ds2, _ := examples.NewDatastore(c2)

    m2, err2 := ds2.GetMenu(ctx, menuUUID)
    assert.NoError(t, err2)
    assert.Equal(t, menu, m2)
}

Documentation

Overview

Package testingexamples is the Examples: Testing.

The example here demonstrates how to write tests for code that uses the DOSA client. For now, we are suggesting the use of a mock client that we have generated using MockGen (https://github.com/golang/mock). It's available as (github.com/uber-go/dosa/mocks).MockClient.

MockClient Usage

Given an entity defined as:

type User struct {
    dosa.Entity `dosa:"primaryKey=UUID"`
    UUID        dosa.UUID
    Name        string
    Email       string
    CreatedOn   time.Time
}

And a method that operates on that entity called GetUser:

type Datastore struct {
    client dosa.Client
}

func (d *Datastore) GetUser(ctx context.Context, uuid dosa.UUID) (*User, error) {
    user := &User{uuid: uuid}
    readCtx, readCancel := context.WithTimeout(ctx, 1 * time.Second)
    if err := d.client.Read(readCts
}

The client behavior can then be mocked using MockClient:

package datastore_test

import (
    "github.com/golang/mock/gomock"
    "github.com/stretchr/testify/assert"

    "github.com/uber-go/dosa"
    examples "github.com/uber-go/dosa/examples/testing"
    "github.com/uber-go/dosa/mocks"
)

func TestGetUser(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    // mock error from `Read` call
    c1 := mocks.NewMockClient(ctrl)
    c1.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c1.EXPECT().Read(gomock.Any(), nil, user).Return(errors.New("Read Error")).Times(1)
    ds1, _ := examples.NewDatastore(c1)

    u1, err1 := ds1.GetUser(ctx, uuid)
    assert.Error(t, err1)
    assert.Nil(t, u1)

    // happy path
    c2 := mocks.NewMockClient(ctrl)
    c2.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c2.EXPECT().Read(gomock.Any(), nil, user).Return(nil).Times(1)
    ds2, _ := examples.NewDatastore(c2)

    u2, err2 := ds2.GetUser(ctx, uuid)
    assert.NoError(t, err2)
    assert.Equal(t, u2, user)
}

A complete, runnable example of this can be found in our testing examples package (https://github.com/uber-go/dosa/tree/master/examples/testing).

EqRangeOp and EqScanOp

In addition to the MockClient, dosa provides two useful gomock.Matchers. EqRangeOp allows you to verify that an expected call to Range is made with a specific RangeOp. EqScanOp does the same thing, except for the Scan function. For instance, assume we have the following entity:

type MenuItem struct {
    dosa.Entity `dosa:"primaryKey=((MenuUUID), MenuItemUUID)"`
    MenuUUID     dosa.UUID
    MenuItemUUID dosa.UUID
    Name         string
    Description  string
}

Let's also assume we add the following receiver function to our DataStore struct:

func (d *Datastore) GetMenu(ctx context.Context, menuUUID dosa.UUID) ([]*MenuItem, error) {
	op := dosa.NewRangeOp(&MenuItem{}).Eq("MenuUUID", menuUUID).Limit(50)
	rangeCtx, rangeCancelFn := context.WithTimeout(ctx, 1*time.Second)
	defer rangeCancelFn()

	objs, _, err := d.client.Range(rangeCtx, op)
	if err != nil {
		return nil, err
	}

	menuItems := make([]*MenuItem, len(objs))
	for i, obj := range objs {
		menuItems[i] = obj.(*MenuItem)
	}
	return menuItems, nil
}

In our tests, we could verify that a particular list of MenuItem entities were queried for using the EqRangeOplike so:

func TestGetMenu(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    expectedOp := dosa.NewRangeOp(&examples.MenuItem{}).Eq("MenuUUID", menuUUID).Limit(50)

    // mock error from Range call
    c1 := mocks.NewMockClient(ctrl)
    c1.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c1.EXPECT().Range(gomock.Any(), dosa.EqRangeOp(expectedOp)).Return(nil, "", errors.New("Range Error")).Times(1)
    ds1, _ := examples.NewDatastore(c1)

    m1, err1 := ds1.GetMenu(ctx, menuUUID)
    assert.Error(t, err1)
    assert.Nil(t, m1)

    // happy path
    c2 := mocks.NewMockClient(ctrl)
    c2.EXPECT().Initialize(gomock.Any()).Return(nil).Times(1)
    c2.EXPECT().Range(gomock.Any(), dosa.EqRangeOp(expectedOp)).Return(objMenu, "", nil).Times(1)
    ds2, _ := examples.NewDatastore(c2)

    m2, err2 := ds2.GetMenu(ctx, menuUUID)
    assert.NoError(t, err2)
    assert.Equal(t, menu, m2)
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Datastore

type Datastore struct {
	// contains filtered or unexported fields
}

Datastore implements methods to operate on entities.

func NewDatastore

func NewDatastore(c dosa.Client) (*Datastore, error)

NewDatastore returns a new instance of Datastore or an error

func (*Datastore) GetMenu

func (d *Datastore) GetMenu(ctx context.Context, menuUUID dosa.UUID) ([]*MenuItem, error)

GetMenu fetches all of the MenuItems for the menu specified by menuUUID.

func (*Datastore) GetUser

func (d *Datastore) GetUser(ctx context.Context, uuid dosa.UUID) (*User, error)

GetUser fetches a user from the datastore by uuid

type MenuItem struct {
	dosa.Entity  `dosa:"primaryKey=((MenuUUID), MenuItemUUID)"`
	MenuUUID     dosa.UUID
	MenuItemUUID dosa.UUID
	Name         string
	Description  string
}

MenuItem represents a single item on a Menu.

type User

type User struct {
	dosa.Entity `dosa:"primaryKey=UUID"`
	UUID        dosa.UUID
	Name        string
	Email       string
	CreatedOn   time.Time
}

User is a user record

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL