Table test not working on Golang with Receiver Function - unit-testing

I am trying to do some unit testing in Golang. I have this filter structure:
tests/
|_ rcv-func.go
|_ rcv-func_test.go
My rcv-func.go looks like this:
package main
import "fmt"
type Player struct {
health, maxHealth int
energy, maxEnergy int
name string
}
func (p *Player) modifyHealth(newHealth int) {
p.health = newHealth
}
func (p *Player) modifyEnergy(newEnergy int) {
p.energy = newEnergy
}
func main() {
player := Player{
health: 50,
maxHealth: 300,
energy: 20,
maxEnergy: 100,
name: "Jose",
}
fmt.Println("Before resting:", player)
(&player).modifyHealth(150)
(&player).modifyEnergy(100)
fmt.Println("After resting:", player)
}
And my rcv-func_test.go like this:
package main
import (
"fmt"
"testing"
)
var tests = []struct {
health int
energy int
expect int
name string
goal bool
}{
{200, 300, 50, "test1", true},
{100, 300, 0, "test2", true},
}
func TestModifyEnergy(t *testing.T) {
for _, tt := range tests {
(&tt).modifyEnergy(11)
}
}
When I try to test the receiver function .modifyEnergy(), the line (&tt).modifyEnergy(11) is giving me the following error:
(&tt).modifyEnergy undefined (type *struct{health int; energy int; expect int; name string; goal bool} has no field or method modifyEnergy) (exit status 2)
What would be the mistake here? It feels it is not defined but the method is clearly defined in the rcv-func.go file.
I tried making both receiver functions Public but to no avail.
Thank you in advance!

Related

How to test Go Mock Repository inside loop on usecase

I have a problem with testing with Repository Mock Database using testify.
I want to test a service/use case that creates a record database for each iteration. Here is the code:
This code contain mock of the database
mockrepository.go
package service
import(
"errors"
"github.com/stretchr/testify/mock"
)
type TestRepositoryMock struct {
Mock mock.Mock
}
func (repository *TestRepositoryMock) CreateTodo(todo *Todo) error {
arguments := repository.Mock.Called(todo)
if arguments.Get(0) == nil {
return errors.New("Error")
} else {
return nil
}
}
func (repository *TestRepositoryMock) CreateTodoDetail(todo *TodoDetail) error {
arguments := repository.Mock.Called(todo)
if arguments.Get(0) == nil {
return errors.New("Error")
} else if arguments.Get(1) == nil {
return errors.New("Error")
} else {
return nil
}
}
the logic inside this use case is to save TodoDetail for each number of items (NumberOfItems variable)
usecase.go
package service
import(
"strconv"
)
type UseCase interface {
SaveTodo(numberOfItems int) (string, error)
}
func NewUseCase(repo Repository) UseCase {
return &useCase{repo: repo}
}
type useCase struct {
repo Repository
}
func (uc *useCase) SaveTodo(numberOfItems int) (string, error){
todo := Todo{
Title: "this is title",
}
uc.repo.CreateTodo(&todo)
for i := 0; i < numberOfItems; i++ {
todoDetail := TodoDetail{
ID: todo.ID,
Item: "item "+ strconv.Itoa(i),
}
uc.repo.CreateTodoDetail(&todoDetail)
}
return "success", nil
}
package service
import(
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var repository = &TestRepositoryMock{Mock: mock.Mock{}}
var testService = useCase{repo: repository}
func TestService_SaveTodoSuccess(t *testing.T) {
todo := Todo{
Title: "this is title",
}
todoDetail := TodoDetail{
ID: todo.ID,
Item: "item 1",
}
repository.Mock.On("CreateTodo", &todo).Return(nil)
repository.Mock.On("CreateTodoDetail", &todoDetail).Return(nil).Once()
result, err := testService.SaveTodo(3)
assert.Nil(t, err)
assert.NotNil(t, result)
}
How to test the multiple call for CreateTodoDetail inside for loop?
-SOLVED-
For testing on the loop use case, we should provide numbers of mock data. same as loop iteration.
Example. If use case has 3 iteration loop that calls the repository three times then we must provide 3 data mock.
the code should be like this:
func TestService_SaveTodoSuccess(t *testing.T) {
// Mock Entity Todo
todo := Todo{
Title: "this is title",
}
// Mock Entity TodoDetail
todoDetail1 := TodoDetail{
ID: todo.ID,
Item: "item 0",
}
todoDetail2 := TodoDetail{
ID: todo.ID,
Item: "item 1",
}
todoDetail3 := TodoDetail{
ID: todo.ID,
Item: "item 2",
}
repository.Mock.On("CreateTodo", &todo).Return(todo)
// calls 3 times "CreateTodoDetail" Repository
repository.Mock.On("CreateTodoDetail", &todoDetail1).Return(todoDetail1)
repository.Mock.On("CreateTodoDetail", &todoDetail2).Return(todoDetail2)
repository.Mock.On("CreateTodoDetail", &todoDetail3).Return(todoDetail3)
result, err := testService.SaveTodo(3)
assert.Nil(t, err)
assert.NotNil(t, result)
}
The scenario builds 3 different data on todoDetail to mock 3 times iterations for CreateTodoDetail repository

Ginkgo: Mocking a method for unit test

Please note that struct S implements the interface I.
I'm trying to test MethodA by mocking the response from MethodB.
sample.go:
package service
// This is implemented by S
type I interface {
MethodA(num int) int
MethodB(num int) int
}
type S struct {
num int
str string
}
func NewI(num int, str string) I {
return S{num, str}
}
func (s S) MethodA(num int) int {
resp := s.MethodB(num) // want to mock this
return 5 * resp
}
func (s S) MethodB(num int) int {
return num * 10
}
sample_test.go :
package service
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type MockI struct {
MockMethodA func(num int) int
MockMethodB func(num int) int
}
func (m *MockI) MethodA(num int) int {
return m.MockMethodA(num)
}
func (m *MockI) MethodB(num int) int {
return m.MockMethodB(num)
}
var _ = Describe("MethodA", func() {
Context("MethodA", func() {
Describe("normal case", func() {
It("should give proper response", func() {
i := NewI(1, "test")
// have to mock methodB()
// something like this:
// i.MethodB = MethodB(num int) int{
// return <some_value>
// }
got := i.MethodA(10)
expected := 500
Expect(got).To(Equal(expected))
})
})
})
})
Any help will be appreciated. Thanks!
Wouldnt the usage of dependency injection work? Inject the MockI into the code that you will be testing.
func funcTobeTested(i I) {
i.MethodA(0)
}
And then on the test:
mockI := MockI{}
// Will run the mock implementation of MethodA
funcTobeTested(mockI)
I think you can use the mockery package to mock the interface and use the .On function of mock package to mock just methodB in testing methodA.

unit testing GraphQL in Golang

in this case I am using
Echo
mongo-driver (MongoDB)
gqlgen graphql type safe
is there any simple example for testing my Mutation and Query ? I do love to get advices for this. I have tried to find but can't found any so far,
thank you :)
Here is an test example using testify package and the gqlgen/client package which is used internally for testing.
GraphQL schema:
type Query {
user(loginname: String!): UserDetail
}
type Mutation {
validateAccessToken(accesstoken: String!): UserEntity
}
type User {
loginname: String
avatarUrl: String
}
type UserEntity {
id: ID!
loginname: String
avatarUrl: String
}
type UserDetail {
loginname: String
avatarUrl: String
githubUsername: String
createAt: String
score: Int
}
graph/resolver/resolver.go:
package resolver
import "github.com/mrdulin/gqlgen-cnode/services"
// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.
type Resolver struct {
UserService services.UserService
}
services/user.go:
package services
type UserService interface {
GetUserByLoginname(loginname string) *model.UserDetail
ValidateAccessToken(accesstoken string) *model.UserEntity
}
graph/resolver/root.resolver.go:
package resolver
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"github.com/mrdulin/gqlgen-cnode/graph/generated"
"github.com/mrdulin/gqlgen-cnode/graph/model"
)
func (r *mutationResolver) ValidateAccessToken(ctx context.Context, accesstoken string) (*model.UserEntity, error) {
return r.UserService.ValidateAccessToken(accesstoken), nil
}
func (r *queryResolver) User(ctx context.Context, loginname string) (*model.UserDetail, error) {
return r.UserService.GetUserByLoginname(loginname), nil
}
// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
Created mock object for UserService:
mocks/userService.go:
package mocks
import (
"github.com/mrdulin/gqlgen-cnode/graph/model"
"github.com/stretchr/testify/mock"
)
type MockedUserService struct {
mock.Mock
}
func (s *MockedUserService) GetUserByLoginname(loginname string) *model.UserDetail {
args := s.Called(loginname)
return args.Get(0).(*model.UserDetail)
}
func (s *MockedUserService) ValidateAccessToken(accesstoken string) *model.UserEntity {
args := s.Called(accesstoken)
return args.Get(0).(*model.UserEntity)
}
graph/resolver/root.resolver_test.go:
package resolver_test
import (
"testing"
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/mrdulin/gqlgen-cnode/graph/generated"
"github.com/mrdulin/gqlgen-cnode/graph/model"
"github.com/mrdulin/gqlgen-cnode/graph/resolver"
"github.com/mrdulin/gqlgen-cnode/mocks"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var (
loginname = "mrdulin"
avatarURL = "avatar.jpg"
score = 50
createAt = "1900-01-01"
)
func TestMutationResolver_ValidateAccessToken(t *testing.T) {
t.Run("should validate accesstoken correctly", func(t *testing.T) {
testUserService := new(mocks.MockedUserService)
resolvers := resolver.Resolver{UserService: testUserService}
c := client.New(handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers})))
ue := model.UserEntity{ID: "123", User: model.User{Loginname: &loginname, AvatarURL: &avatarURL}}
testUserService.On("ValidateAccessToken", mock.AnythingOfType("string")).Return(&ue)
var resp struct {
ValidateAccessToken struct{ ID, Loginname, AvatarUrl string }
}
q := `
mutation {
validateAccessToken(accesstoken: "abc") {
id,
loginname,
avatarUrl
}
}
`
c.MustPost(q, &resp)
testUserService.AssertExpectations(t)
require.Equal(t, "123", resp.ValidateAccessToken.ID)
require.Equal(t, "mrdulin", resp.ValidateAccessToken.Loginname)
require.Equal(t, "avatar.jpg", resp.ValidateAccessToken.AvatarUrl)
})
}
func TestQueryResolver_User(t *testing.T) {
t.Run("should query user correctly", func(t *testing.T) {
testUserService := new(mocks.MockedUserService)
resolvers := resolver.Resolver{UserService: testUserService}
c := client.New(handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers})))
u := model.UserDetail{User: model.User{Loginname: &loginname, AvatarURL: &avatarURL}, Score: &score, CreateAt: &createAt}
testUserService.On("GetUserByLoginname", mock.AnythingOfType("string")).Return(&u)
var resp struct {
User struct {
Loginname, AvatarURL, CreateAt string
Score int
}
}
q := `
query GetUser($loginname: String!) {
user(loginname: $loginname) {
loginname
avatarUrl
createAt
score
}
}
`
c.MustPost(q, &resp, client.Var("loginname", "mrdulin"))
testUserService.AssertCalled(t, "GetUserByLoginname", "mrdulin")
require.Equal(t, "mrdulin", resp.User.Loginname)
require.Equal(t, "avatar.jpg", resp.User.AvatarURL)
require.Equal(t, 50, resp.User.Score)
require.Equal(t, "1900-01-01", resp.User.CreateAt)
})
}
test result:
=== RUN TestMutationResolver_ValidateAccessToken
=== RUN TestMutationResolver_ValidateAccessToken/should_validate_accesstoken_correctly
TestMutationResolver_ValidateAccessToken/should_validate_accesstoken_correctly: root.resolvers_test.go:44: PASS: ValidateAccessToken(mock.AnythingOfTypeArgument)
--- PASS: TestMutationResolver_ValidateAccessToken (0.00s)
--- PASS: TestMutationResolver_ValidateAccessToken/should_validate_accesstoken_correctly (0.00s)
=== RUN TestQueryResolver_User
=== RUN TestQueryResolver_User/should_query_user_correctly
--- PASS: TestQueryResolver_User (0.00s)
--- PASS: TestQueryResolver_User/should_query_user_correctly (0.00s)
PASS
ok github.com/mrdulin/gqlgen-cnode/graph/resolver 0.141s
test coverage report:
source code: https://github.com/mrdulin/gqlgen-cnode

Mock random generator in Go

For my tests purpose, I would like to mock random numbers in Go. So I created the Random interface. During unit testing I return the identity function, while for implementation I generate a random number with rand package.
It is the right way for mocking random numbers in Go? Any help appreciated.
Go Playground: https://play.golang.org/p/bibNnmY2t1g
main:
package main
import (
"time"
"math/rand"
"fmt"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
type Random interface {
Uint(_ uint) uint
}
type rndGenerator func(n uint) uint
type Randomizer struct {
fn rndGenerator
}
func NewRandomizer(fn rndGenerator) *Randomizer {
return &Randomizer{fn: fn}
}
func (r *Randomizer) Uint(n uint) uint {
return r.fn(n)
}
func fakeRand(n uint) uint { return n }
func realRand(_ uint) uint { return uint(rand.Uint64()) }
func main() {
fakeRnd := NewRandomizer(fakeRand).Uint
fmt.Println(fakeRnd(1))
fmt.Println(fakeRnd(2))
realRnd := NewRandomizer(realRand).Uint
fmt.Println(realRnd(0))
fmt.Println(realRnd(0))
}
test:
package main
import (
"testing"
"math/rand"
"reflect"
)
func TestNewRandomizer(t *testing.T) {
fn := func(n uint) uint { return n }
type args struct {
fn rndGenerator
}
tests := []struct {
name string
args args
want *Randomizer
}{
{
"test",
args{fn},
&Randomizer{fn},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewRandomizer(tt.args.fn); reflect.TypeOf(got) != reflect.TypeOf(tt.want) {
t.Errorf("NewRandomizer() = %v, want %v", got, tt.want)
}
})
}
}
func TestRandomer_Uint(t *testing.T) {
rnd := uint(rand.Uint64())
type fields struct {
fn rndGenerator
}
type args struct {
n uint
}
tests := []struct {
name string
fields fields
args args
want uint
}{
{
"test",
fields{func(n uint) uint { return n }},
args{rnd},
rnd,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Randomizer{
fn: tt.fields.fn,
}
if got := r.Uint(tt.args.n); got != tt.want {
t.Errorf("Randomizer.Uint() = %v, want %v", got, tt.want)
}
})
}
}
func Test_fakeRand(t *testing.T) {
rnd := uint(rand.Uint64())
type args struct {
n uint
}
tests := []struct {
name string
args args
want uint
}{
{
"test",
args{rnd},
rnd,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := fakeRand(tt.args.n); got != tt.want {
t.Errorf("fakeRand() = %v, want %v", got, tt.want)
}
})
}
}
func Test_realRand(t *testing.T) {
type args struct {
in0 uint
}
tests := []struct {
name string
args args
want bool
}{
{
"test",
args{0},
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := realRand(tt.args.in0); got < 1 {
t.Errorf("realRand() = %v, want %v", got, tt.want)
}
})
}
}
Your example makes no real use of the Random interface since the mocking is being done at the function field level of the Randomizer type.
I would recommend, if possible, to ditch the function field as well as the functions and instead define two separate implementations of the Random interface. You can use empty structs for this, they may look weird at first but they have the nice property of taking up 0 bytes of memory.
The main reason for the recommendation is that when you use function fields you lose the ability to compare your struct type values with reflect.DeepEqual. This is because two function values are only equal if they have the same type and both are nil.
As an example let's first look at your TestNewRandomizer which is a symptom of the issue stated above. In the test you're just comparing the type of the return value which is something already ensured by the compiler, so the test is absolutely pointless.
Now, let's say you drop the test, since it's useless, but for some reason you keep the function field. Because of this any struct type that depends on *Randomizer will also be untestable with DeepEqual and you'll have the same difficulties when trying to come up with a test for that type.
package main
import (
"time"
"math/rand"
"fmt"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
type Random interface {
Uint(_ uint) uint
}
type Randomizer struct {}
func NewRandomizer() Randomizer {
return Randomizer{}
}
func (r Randomizer) Uint(n uint) uint {
return uint(rand.Uint64())
}
type FakeRandomizer struct {}
func NewFakeRandomizer() FakeRandomizer {
return FakeRandomizer{}
}
func (r FakeRandomizer) Uint(n uint) uint {
return n
}
func main() {
fakeRnd := NewFakeRandomizer().Uint
fmt.Println(fakeRnd(1))
fmt.Println(fakeRnd(2))
realRnd := NewRandomizer().Uint
fmt.Println(realRnd(0))
fmt.Println(realRnd(0))
}
Note that i'm intentionally returning values instead of pointers since empty structs are smaller than pointers.
I have a method which generates a random integer and returns true if the integer is less than or equal to 50 and false if the integer is greater than 50 in the range [0, 100).
This is how I have created my structures to mock the functionality:
type Decider struct {
RandImpl func(int) int
}
func (d *Decider) Decide(randRange int) bool {
randVal := d.RandImpl(randRange)
log.Info("RandVal: ", randVal)
if randVal <= 50 {
return true
}
return false
}
I'm calling this method in this manner:
rand.Seed(time.Now().UnixNano())
decider := decide.Decider{
RandImpl: func(x int) int { return rand.Intn(x) },
}
decider.Decide(100)
In my _test.go file, I have this:
decider := Decider{
RandImpl: func(x int) int { return 42 },
}
ret := decider.Decide(100)
assert.True(t, ret)
This way you can mock the functionality of the random number generator.

How to parse dynamodb result to an integer?

I'm unable to unmarshall a fairly simple data structure:
"video_lite": { "id": 1573, "name": "Blade Runner (Movie)" }
Here's my code that doesn't work:
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Video struct {
video_lite struct {
name string
id int
}
}
func check(err error) {
if err != nil {
panic(err.Error())
}
}
func main() {
svc := dynamodb.New(session.New())
input := &dynamodb.GetItemInput{
Key: map[string]*dynamodb.AttributeValue{"uuid": {S: aws.String("d610e853-5222-462c-9bb3-26ff5aa86e9d")}},
ProjectionExpression: aws.String("video_lite"),
TableName: aws.String("staging_video_ingestion"),
}
result, err := svc.GetItem(input)
check(err)
fmt.Printf("%+v\n", result.Item)
var t Video
err = dynamodbattribute.UnmarshalMap(result.Item, &t)
check(err)
fmt.Printf("%+v\n", t)
}
The output looks like:
map[video_lite:{
M: {
id: {
N: "1573"
},
name: {
S: "Bladerunner (Movie)"
}
}
}]
{video_lite:{name: id:0}}
Why doesn't the UnmarshalMap work?
Unmarshal instead of UnmarshalMap appears to be easier to work with.
type Video struct {
Name string `dynamodbav:"name"`
ID int `dynamodbav:"id"`
}
I threw in the dynamodbav struct tags in an act of desperation. It appears they are not needed when unmarshalling. And now I return the map value, instead of the whole map result.Item which I never figured out how to get to work with UnmarshalMap. :/
err = dynamodbattribute.Unmarshal(result.Item["video_lite"], &t)
Probably you can modify your struct to this :
type Video struct {
video_lite struct {
name struct {
N *string
S *string
}
id struct {
N *string
S *string
}
}
}