go - Golang with Martini: Mock testing example -


i have put piece of code on route. test using mocking. go , test noob, tips appreciated.

my generate routes.go generates routes current url. snippet:

func (h *stateroute) generateroutes (router *martini.router) *martini.router {     r := *router      /**      * states      *       */     r.get("/state",  func( enc app.encoder,             db abstract.mongodb,             reqcontext abstract.requestcontext,             res http.responsewriter,             req *http.request) (int, string) {          states := []models.state{}          searchquery := bson.m{}          var q *mgo.query = db.getdb().c("states").find(searchquery)         query, currentpage, limit, total := abstract.paginate(req, q)         query.all(&states)          str, err := enc.encodewithpagination(currentpage, limit, total, states)          return http.statusok, app.wrapresponse(str, err)     }) } 

and being called in server.go such:

var configuration = app.loadconfiguration(os.getenv("myenv"))  // our martini api instance var apiinstance *martini.martini  func init() {      apiinstance = martini.new()     // setup middleware     apiinstance.use(martini.recovery())     apiinstance.use(martini.logger())      // add request context middleware support contexual data availability     reqcontext := &app.lrscontext{ }     reqcontext.setconfiguration(configuration)      producer := app.configproducer(reqcontext)     reqcontext.setproducer(producer)      apiinstance.mapto(reqcontext, (*abstract.requestcontext)(nil))      // hook in oauth2 authorization object, processed before requests     apiinstance.use(app.verifyauthorization)      // connect db , inject db connection martini     apiinstance.use(app.mongodbconnect(reqcontext))      // add responseencoder allow json encoding of our responses     apiinstance.use(app.responseencoder)      // add route handlers     r := martini.newrouter()      staterouter := routes.stateroute{}      staterouter.generateroutes(&r)      // add built router martini action     apiinstance.action(r.handle) } 

my doubts:

  1. how mocking work here, considering trying inject dependency?

  2. where should start testing i.e. should mock r.get in generate routes? right now, i've done since i'm using martini handles routing , requests, i'm quote lost if i've done right?

state_test.go:

type mockedstateroute struct {     // how can mock stateroute struct?     mock.mock } type mockedencoder struct {     mock.mock } type mockedmongodb struct {     mock.mock } type mockedreqcontext struct{     mock.mock } type mockedrespwriter struct{     mock.mock } type mockedreq struct{     mock.mock }  func (m *mockedstateroute) testgetstatesroute(m1 mockedencoder,                     m2 mockedmongodb, m3 mockedreqcontext,                     m4 mockedreqcontext, m5 mockedrespwriter,                     m6 mockedreq) (string) {                         args := m.called(m1,m2,m3,m4,m5,m6)                         fmt.print("you called /states/get")                         // 1 test value want return                     return 1, args.error(1) }  func testsomething (t *testing.t) {     testobj := new(mockedstateroute)      testobj.on("testgetstatesroute", 123).return(true,nil)      // target function mockedstateroute     // how can call function in generateroutes(). or should i, since martini handling requests } 

links i've referred to:

  1. /stretchr/testify/mock doc
  2. examples of 1.

for doing dependency injection, thing test needs have way receive dependencies. in code connection mongodb done in initialization of thing test itself, doesn't allow inject looks mongo connection, while being mock.

there many ways of achieving it, 1 of simplest , direct ways dependency injection, make thing test receive dependency when it's created, way context place specific implementation of dependency configured. take this example:

type datastore interface {     get(k string) string     set(k, v string) }  type myinstance struct {     *martini.martini }  func newappinstance(d datastore) *myinstance {     ... }  func main() {    d := newredisdatastore("127.0.0.1", 6379)    newappinstance(d).run() } 

the instance needs implementation of datastore work, doesn't have know internals, thing matters implements interface, both methods, get , set. indeed, general rule in unit testing, want test code, not dependencies. in example, uses redis in "production", but, in testing:

type mockeddatastore struct {     mock.mock }  func (m *mockeddatastore) get(k string) string {     args := m.called(k)     return args.string(0) }  func (m *mockeddatastore) set(k, v string) {     m.called(k, v) } 

it's without functionality beyond letting framework check has been called. in test have configure expectations things like:

d := new(mockeddatastore) ... d.on("set", "foo", "42").return().once() ... d.on("get", "foo").return("42").once() 

and, of course, initialize instance mocked thing, , test it:

d := new(mockeddatastore) instance := newappinstance(d) d.on("get", "foo").return("42").once() request, _ = http.newrequest("get", "/get/foo", nil) response = httptest.newrecorder() instance.servehttp(response, request) d.assertexpectations(t) 

so, summary, being more specific answers questions:

  1. you need make instance able initialized dependencies, e.g. creating method receives dependencies , returns instance. mock dependencies , test use mocks instead of "real" ones.

  2. use method servehttp martini provides generate responses http requests, , httptest.newrecorder() simulate reception of response. of course, if application have more complex functionality used apart of http interface, can test normal methods.


Popular posts from this blog