goware / geotools

Geo-location lookup library / service built on Google Maps API
MIT License
2 stars 1 forks source link

mocking #8

Closed pkieltyka closed 8 years ago

pkieltyka commented 8 years ago

The mocking in this library feels very strange, brittle and error-prone. I don't have a ton of mocking experience, but the code here looks like its doing mocking via a mixin using build tags. Mocking is only useful for tests, so why dont we use _test.go for the test portion of the code? .. I think we need to heavily refactor how we are mocking in this library.

cc: @VojtechVitek @c2h5oh

VojtechVitek commented 8 years ago

The most common approach is to have an interface and define its implementations (1) and then use dependency injection (2):

1:

// whatever.go
package whatever

type interface Interface {
  Do() error
}

type Whatever struct {
}

func (w *Whatever) Do() error {
  // implementation
}

var _ Interface = &Whatever{} 
// whatever_test.go
package whatever_test

import "github.com/pressly/geoy/whatever"

type WhateverMock struct {
}

func (w *WhateverMock) Do() error {
  // mock implementation
}

var _ whatever.Interface = &WhateverMock{} 

2:

// main.go
import "github.com/pressly/geoy/whatever"

func main() {
   w := &whatever.Whatever{}

   app := NewApp(w)
   // app uses real implementation
   // ...
}
// whatever_test.go

func TestWhatever(t *testing.T) {
   w := &MockWhatever{}

   app := NewApp(w)
   // test app uses mock implementation
   // ...
}
xiam commented 8 years ago

My initial approach was recording all the input and output we got from the google maps API, since we can't just fake a server and get mock respondes (actual Google Maps endpoints are never exposed, nor cannot be changed).

The reason I am using build tags is that this mock takes place here in geoy, here is where responses are emulated and not in the file we want to test (which is outside geoy).

I am open to suggestions, I agree that it would be better to keep this as part of the files we want to test.

pkieltyka commented 8 years ago

@xiam your approach makes sense, but I think it works outside of Go's conventional ways, and makes other things more difficult. Can you refactor the mocks based on Vojtech's suggestions? ie. we could export an interface from geoy called like..

Finder with the methods that we use to look up location/place data just like you've done. Then, we can implement a MapsClient based on Finder interface using Google Maps API .. and again, we can make a Mock client easily this way.