Working toward a testable Sinatra application

One of the prime goals I had when starting writing a simple Sintra application was to make sure unit testing was done from the start, a vague sort of TDD, given that I’m not  professional developer and I’m not mad about ideaology; I’d had made very little trying to build unit tests for Rails applications, especially when it comes to sessiosn and authentication. No testing, no application.

Even though Sinatra is a small footprint and quick to get going, I still found it very opaque and the Rack test library very secretive and deceptive. It took me 10 days trying to figure out 4 tests for my application, though, as painful as it was, I do have a better (and more coherent – never my strong point) application as a result.

Ultimately, however, I found it much easier to design the testing code for the transactions I wanted using curl because it is so much easier to figure out what is going on.  I really wanted to run a command that I *knew* was submitting data in the format I wanted so that I could sort the routing code around it. Something like,

curl -v http://localhost:4567/package-inventory/packages/new -H 'Content-Type: application/json' -d '{"hostname": "thisbox", "packages": {"first-package": "4.9.", "my-package": "1.2.", "your-package": "4.5.6-0."}}'

Once the server is reponding as expected, it can easily be added to an integration test with a snippet like

jdata = {}
 jdata[:hostname] = hostname
jdata[:packages] = {}
 ["first-package 4.9.0", "my-package 1.2.3", "your-package 4.5.6-0.1"].each do |pkg|
  jdata[:packages].merge! Hash[*pkg.chop.split(/ /)]
 end

The submission can be completed using something like

 request = '/package-inventory/packages/new'
 headers = { 'CONTENT_TYPE' => 'application/json' }
 post request, jdata.to_json, headers
 assert last_response.ok?

On the receiving end of the POST we hve to remember that the incoming data is a SringIO object and as such is accessed like a file stream,

jd = request.body.read.to_s
 jdata = JSON.parse jd

I initially made the mistake of treating the request body as an array to be referenced several times and wondering why it had disappeared: assign it to a variable an be done with it! I also spent some time trying to access the submission through the params hash without realising that that only applies to symbolised references on the incoming request.

After parsing, we then have our data to do as we please. Based on an example, I maintained the return messages (for status or data return) as a hash finishing off each route with,

return_message.to_json

helping ensure that all inbound and outbound requests are in the same format.

I still wouldn’t say that I’m fully comfortable with the unit tests, but they do work mostly as expected, even for failure conditions.

But as a comparative exercise, I’m going to produce Python version of the same service using Flask and a unit test process, bearing in mind that this will be my first ever Python program; the early signs are quite promising.

References:

I found the last comment at http://stackoverflow.com/questions/18449428/sinatra-unit-test-post-with-json-body (eventually) useful, but ignore the comment advising against using JSON to transfer data; such is the variability of the Stack.

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s