In the previous blog post, I demonstrated how to stub EM::HttpRequest calls using the built in EventMachine::MockHttpRequest module. While that is sufficient if you are sorely using EM::HttpRequest as your sole http client, it would mean refactoring the test code again if the client changes.
We want to make the stub calls as generic as possible so it is not tightly coupled to a specific http client implementation.
WebMock is the ideal library to utilise in this case. It is a http stubbing library that works with various popular Ruby Http clients including EM and Net::HTTP amongst others. It has a self explanatory interface and provides options to tailor your stub calls including setting request headers and body responses. In addition, it also allows you to match stub request calls based on regular expressions, which makes it even more flexible to adapt to your own test code if your application accesses various external API endpoints.
WebMock, by default, makes the external API request call so you would need to disable it using the following commands:
To re-enable it, simply use: WebMock.allow_net_connect! Since these commands may be used multiple times within your spec files, I tend to put them within methods inside spec_helper.rb
<script src=”https://gist.github.com/790144.js”> </script>
The WebMock.reset! command clears the WebMock request registry so it treats each stub request call as a new request. This comes in useful when you want to test the number of times a particular request has been made using the following matcher: WebMock.should have_requested(:get,<my url>.once
The stub request need to be initiated before the actual call is made. It takes the following format: stub_request(METHOD,<URL>||<REGEXP>).with(<REQUEST BODY>).to_return(HASH OF OPTIONS such as body,status,headers)
<script src=”https://gist.github.com/790149.js”> </script>
The syntax is self explanatory - thats the beauty of using WebMock. Essentially what the line above does is to stub out your request to @post_regexp which will be a url to your external api using the POST action; with the parameters of the request defined in the body hash ; and finally to return a hash of response which includes status code, header, and body.
You will need to include the stub call before making any actual requests else you will receive ‘Request not registered errors in the console’. The reason this occurs is that within the WebMock gem, it keeps an internal hash of url requests and if its not stubbed out will attempt to make an actual request.
There are some pitfalls to avoid when using WebMock in my own experience:
Firstly, if you are running a local service such as a SOLR server, in your WebMock.disconnect call, you need to pass in ‘allow_localhost => true’ else WebMock will just register all your local calls to be unregistered.
Secondly, within autotests , you might have to stub out the same request twice from my own experience. Not sure if thats a configuration issue on my end or the way autotests work.
Thirdly, if you are using older versions of Rspec, you need to explicitly include the following into your spec_helper.rb file to use the matchers:
If you are unsure of how to structure your stub requests, I will be following this up with some more examples of using WebMock in the wild in my own projects.