How to use mocking and session interchangeably?
sankethpb opened this issue · comments
Hello @CMogilko @dancannon and all,
Am beginner in golang and rethinkDB. I was trying to use session and mock interchangeably in production and unit testing like shown below.
Requirement:
I have a http POST handler which receives a Person struct and saves to rethink db. In production I want to pass a real session of RethinkDB and in unit test I want to pass mock db and perform further test queries on mock either directly or using other handlers.
I tried this with below sample code, but I get below error when I run unit tests.
Could you please help me here and also clarify how I would be able to achieve such a functionality?
Error:
--- FAIL: Test_PersonPost (0.00s)
exit status 2
FAIL rethinkDBTrial 4.041s
panic: gorethink: mock: This query was unexpected:
r.DB("person").Table("person").Insert({name="myname", age=20}) [recovered]
panic: gorethink: mock: This query was unexpected:
r.DB("person").Table("person").Insert({name="myname", age=20})
//file: main.go
package main
import (
"rethinkDBTrial/db"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
r "gopkg.in/gorethink/gorethink.v3"
)
type person struct {
Name string `gorethink:"name" json:"name"`
Age int `gorethink:"age" json:"age"`
}
//new iris app, pass rethinkDB session or mock session here
func newApp(dbSession interface{}) *iris.Application {
app := iris.New()
//Post handler to post a person struct
app.Post("/person", func(ctx context.Context) {
//unmarshal person
per := &person{}
err := ctx.ReadJSON(per)
if err != nil {
ctx.StatusCode(iris.StatusNotAcceptable)
ctx.WriteString(err.Error())
} else {
//Insert data to database, assert dbSession as QueryExecutor
table, err := r.DB("person").Table("person").Insert(per).Run(dbSession.(r.QueryExecutor))
if err != nil {
ctx.StatusCode(iris.StatusExpectationFailed)
ctx.Writef("Cannot insert %v\n", err)
}
table.Close()
}
})
return app
}
func main() {
//Initialize app with real db session
app := newApp(db.GetSession())
app.Run(iris.Addr(":8090"))
}
//file: db/db.go
package db
import (
r "gopkg.in/gorethink/gorethink.v3"
)
var session *r.Session
func init() {
var err error
session, err = r.Connect(r.ConnectOpts{
Address: "localhost:28015",
})
if err != nil {
panic(err.Error)
}
tableName := "person"
r.DBList().Contains(tableName).Do(r.DBCreate(tableName).Exec(session)).Run(session)
r.DB(tableName).TableCreate(tableName).Exec(session)
}
//GetSession of DB
func GetSession() *r.Session {
return session
}
//file: main_test.go
package main
import (
"testing"
"github.com/kataras/iris/httptest"
r "gopkg.in/gorethink/gorethink.v3"
)
func Test_PersonPost(t *testing.T) {
mockDB := r.NewMock()
mockDB.On(r.DBCreate("person"))
mockDB.On(r.DB("person").TableCreate("person"))
app := newApp(mockDB)
testServer := httptest.New(t, app)
per := &person{"myname", 20}
testServer.POST("/person").WithJSON(per).Expect().Status(httptest.StatusOK)
//further assertions / queries on mock db directly or using other Get / Patch handlers
}
@sankethpb Hello! I've noticed that you call DBCreate
and TableCreate
in init()
function.
In your unit-test package db
isn't imported so there is no db.init()
invocation and consequently no DBCreate
and TableCreate
invocation.
First of all you should learn how init
function works:
@sankethpb usage of init()
is very bad especially for connecting db because of it cannot be tested. So you need to create db and tables in any other testable function.
Also, you need to return values from mock, see the stretchr/testify
examples.
You get error because your mock expects 2 calls:
- DBCreate
- TableCreate
Butinit
func cannot be tested so this functions are not called. Instead of it, you runPOST
that callsinsert
that your mock doesn't expect.
thank you for your comments and suggestions. Using init function was a bad example here, this is a sample code, so please ignore this part.
Is there any slack or Gitter channels available for few more clarifications regarding this?
I think this place is not appropriate for a discussion.
@sankethpb https://rethinkdb.com/blog/community-slack/ it has gorethink channel.