From Monkey Patching to integrating Ginkgo BDD Framework in Golang

mourya venkat
5 min readJan 11, 2020

--

This will be a series of posts where I keep writing about our journey from Monkey Patching -> GoMock -> Testify -> Eliminating all 3rd party tools and use Golang composition for mocking -> Integrating Ginkgo for better organising of tests.

Coming from JavaScript background where writing unit tests was just a cake walk, it became next to impossible for me to structure GO code with proper interfaces and mocking the external libraries while writing unit tests.

We have gone through many articles on how to write clean code and how to write loosely coupled code that makes mocking a cake walk. After going through a ton of articles these are the ways I found to write unit tests.

Tightly Coupled External Modules with Code

  • Monkey Patching is the only option for you

Loosely Coupling external modules by accepting interfaces and working on top of methods passed via interfaces. In this way there are multiple options for us.

  • Option-1 Using external third party libraries ( GoMock or Testify )
  • Using Golang Composition without any external libraries. This allows the developer to have more control over the test cases.

Well, in this blog post I will try to cover the path we’ve been through from monkey patching -> Go Mock -> Testify - > With Plain Go lang Composition > Integrating Ginkgo, a BDD framework for organising our test suite.

Well before going further let’s first get some use case which describes what’s a loosely coupled code & what’s a tightly coupled code.

Consider the above scenario where we receive a HTTP Request from the client. main.go is the entry point and passes the request to package1 -> function which depends on some data residing in Database. It then gets the data & calls package2 with the data which depends upon a HTTP(net/http) package which makes a HTTP call to some external service & return data to client.

Now that you’ve got some understanding on what the scenario is let’s try how to write Tightly Coupled Code & using Monkey Patching For writing test cases for the same.

package1

package2

Now if you see package1 and package2 functions are tightly coupled with SQL and HTTP Client package. Now when writing test cases there is no way left for us to mock. Is there any ??? . Monkey Patching , an ugly way is the only way to do it.

We slightly restructured the code this way. Wherever we are calling external modules methods, we initialised those functions to a variable for every file at global level. The following way.

If you look at line number 10, we declared the httpClient.Do to a variable at global level which is accessible to all other files in the same package. (We are going to use this property and override the httpClient.Do in our test suite.

Let me explain you line by line what had happened.

When I wrote the logic for httpClient Module I assigned httpClient.Do functionality to a variable that can be changed by any other function within the package.

So by using this loophole in Go, I placed my test file in the same package and when running my test file, I initially copy the reference of actual Do functionality to a variable & on completion of function (In defer block) I am again reassigning the actual reference back to the Do functionality. The reason being, on line 15 I am changing the reference of DoFunctionality with my mock functionality.

So when the test case executes, instead of making actual HTTP connection, it calls our mock Do functionality and returns a mock response. Once the mock response is returned the application logic and parsing will be executed and the response will be returned back.

In this way, we are writing some tightly coupled code and doing some monkey patching( Overriding the reference of functions over time) so that we can write our tests without making an actual request to the external service.

Ain’t this looks ugly. Not sure about you but for me this looks way to ugly and is 100% error prone as I won’t be able to know which function is changing the reference of which function.

To overcome the pain of monkey patching we have refactored our code by using Methods( bound to a struct) and passing dependencies as interfaces.

In this way the parent implements all the dependencies and pass that to the child functions which accepts interfaces . (This pattern is called Sleeper Cell Pattern) .

The child doesn’t know who’s actually calling it , all it bothers is if all the required functionality required for it is implemented or not. (That’s how a sleeper cell functions. They are some silent services which waits for instructions over a channel & once they receive order through the channel they don’t worry about who actually passed them the instruction. They simply execute their action. )

How we implemented the Sleeper Cell Pattern & How we have integrated GinkGo into our application will be discussed in the continuation of this article.

************************ Stay Tuned ****************************

--

--

mourya venkat
mourya venkat

Written by mourya venkat

I will starve to death if you don’t feed me some code. Quora : https://www.quora.com/profile/Mourya-Venkat-1

No responses yet