Sinatra is a fantastic lightweight framework for building web services. We’ll use it as the application framework for the HTTP endpoints in our Service Oriented Architecture.
The testing approach will be in-process, which means that the test suite is running in the same Ruby process as the web service. This eliminates the need to run an external HTTP web server.
Application structure
Unlike Rails, Sinatra isn’t all that opinionated on how you set up your application (it has a few sensible defaults), which can lead to a lot of open questions on how to structure the application.
Here’s the directory structure we’ll use for our example application.
app/
app/models
app/my_service.rb
client/
client/lib/my_client.rb
client/my_client.gemspec
config/
spec/
Outside-in development with a Client Gem
For internal services we’ll build a client gem directly into the project. With the client embedded in our codebase we can follow outside-in development cycles – Features start with request specs from the client side, followed by the addition of end points to the service, and then unit tests within the application.
This allows the us to dogfood our client gem and bring it in as the first step of our development process.
To achieve this we need to configure a few things.
Set up the project gemfile to use a local copy of the client in test mode
Include the local client gem in test suite.
# Gemfile group :test do gem 'my_client', path: 'client' gem 'webmock' # ... end
Use webmock to send all http requests to the service
Instead of booting up a web server every time the test suite is run we’ll mount the Sinatra service as a rack application with webmock.
This allows the client to talk directly to the mounted rack application without going through HTTP or a web server.
# spec/spec_helper.rb RSpec.configure do |config| config.include WebMock::API config.before(:each) do MyClient.base_url = 'http://www.example.com' stub_request(:any, /www.example.com/).to_rack(MyService) end end
Use the client in our request specs
Once
MyService
is mounted as a rack application we can use the client gem directly in our test suite.# spec/requests/widget_management_spec.rb require 'spec_helper' describe "Widget management" do it "creates a Widget" do # set up fixture data if needed response = MyClient::Widget.create(widget_params) # assert expectations on the response end end
Private gem hosting
To use the client gem in other projects we can use a private gem hosting service like Gemfury. This allows us to include the client via gemfile in our other projects.
# Gemfile
source 'https://452f6E403CDph10714e41@gem.fury.io/me/'
gem 'my_client'
source 'https://rubygems.org'
# ...
Takeaways
- Sinatra is great framework for creating lightweight web services.
- Webmock allows us to test the client in-process against a rack application.
- Use private gem hosting to distribute the shared client.