Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing mGo

I have a function that accepts a database *mgo.Database parameter.

func myFunc(db *mgo.Database) {
// does some operations with db
}

I would like to write a unit test and pass in a mocked db object, but I'm having a very difficult time figuring out how to do that with golang. In other languages I could use there testing frameworks to do a myMock = createMock("Class to Mock"), but with Go I'm not sure how to do this.

I glanced at gomock, but wasn't sure if that is the only way, and wasn't sure how to use the mockgen tool with mgo.

I also thought maybe to write an interface that has all of the same methods as mgo.Database and pass a "mocked" object that uses the interface, and then create an object that uses the interface and passes calls through to mgo's library (similar to an ORM), but that seems like a lot of coding.

like image 828
K2xL Avatar asked Apr 08 '14 16:04

K2xL


1 Answers

*mgo.Database is a pointer to a type, not an interface, you can't mock it.

As in other languages - you need to provide a level of indirection, so that you can provide a real object in production but a mock for testing. So your first step is to extract the interface that your "myFunc" uses (which methods it calls), then you can provide *mgo.Database in production and your mock (manual mock or using some mocking framework) for testing.

This free sample chapter from great book "The Art of Unit Testing" explains the steps you need to do on page 52 (chapter 3, "Using stubs to break dependencies" - "3.3 Determining how to easily test LogAnalyzer"):

http://www.manning.com/osherove/SampleChapter3.pdf

given that in Go a type implements the interface just by implementing the interface's methods - it's even easier than in other languages (like C# for example)

so the answer is as you said

to write an interface that has all of the same methods as mgo.Database and pass a "mocked" object that uses the interface, and then create an object that uses the interface and passes calls through to mgo's library (similar to an ORM), but that seems like a lot of coding.

except that you don't need to create an object that uses the interface and passes calls through to mgo's library (similar to an ORM) because *mgo.Database will implicitly satisfy your interface. So it's not a lot of coding.

like image 70
Kluyg Avatar answered Oct 14 '22 12:10

Kluyg