Project Ramon

A learning journey from a Ruby noob perspective

Lunch Panoply: Rewriting specs for Behavior Coverage.

api12_header_img

Hello and happy Wednesday!

Yesterday, I spent a lot of time working towards attempting to test web service requests and responses. I did not feel confident that my green specs from my Adapter class were really providing the coverage that would be considered acceptable.

I received some very good instruction from Marek yesterday. Thank you Marek! I am looking forward to having the time to dig into the Pragmatic Programmer and Gang of Four books per your suggestion. You can see his actual instruction in the comments section from yesterday’s post.

Here’s a snippet from his comment from yesterday:

api12_img1

Focusing on Behavior not Implementation

Rookie mistake on my end :). I’ve been instructed about this in the past and remember a scenario one of my mentors shared about not needing to ensure that a third party dependency is working. Its more than likely that developers of these gems and such have already written test coverage for their interface’s behavior, and thus, no immediate need to replicate coverage in my application.

I will make an assumption that even though these rules aren’t written in stone. To start off, I should be working out how to write coverage that will allow me to discover whether my behaviors perform as I have intended. That certainly wasn’t my focus before reading Marek’s comment yesterday.

Here are a few articles I’ve read on this topic that provided some good insights, I’ll show you a snippet from this first link as I found it very valuable:

api12_img2

Here is the link to the full StackOverflow discussion.

Here’s a snippet from a blog post by Nick Gauthier:

api12_img3

And here’s the link to his full post, there is a good discussion in the comments.

With these sort of thoughts in mind, lets see how we can re-write this test with behavior expectations as the spearhead of our focus.

change this subtitle

Lets look at my test file from yesterday, so we can have something to look at as we move forward.

api12_img4

I like the first spec which describes our retrieve method from our adapter class. This method’s behavior is to pass filters through into a request to send to the web service, and it expect to collect the objects so we are expecting to be contained in an array.

Moving down to the all method, we have two contexts laid out, one for a successful transaction and the other for an unsuccessful transaction. I’ll rename the upon success and upon failure to successful and unsuccessful transaction as it may slightly better describe the contexts’ behavior.

The next thing I see that I would like to consider changing are the spec strings themselves. Instead of making a Faraday request be the behavior, I should check for the behavior of returned data in a successful transaction and should expect an error response in the event that no data is returned.

Here’s a peak at the changes to my phraseology to better illustrate the behavior being captured:

api12_img6

Lets work on the first spec inside our all method.

it ‘returns successful response

For this spec, we want to make sure that the all methods behavior is such that it contains a 200 series status code inside of the response header. Here’s a link to a site with status codes and their meanings.

From watching my recent AirPair videos I could do better at getting in the habit of thinking before typing when writing expressions. I realize this is a self-explanatory mental step for most of you, even other newbies. It just happens to be an area where I could benefit from improving, so here we go.

In this spec, I’m checking for a success code to be included in the response. These are sent with every HTTP request/response package. Here are a two illustrations that helped me out a while back in visually understanding an HTTP request message’s components and component placement.

HTTP Request Message Illustrations
api12_img7

api12_img8

HTTP Response Message Illustrations
api12_img9

api12_img10

Back to Our Specs
Oops. I think it may be better to create our own success message, I would feel more comfortable using success codes in a controller spec, as I’m not sure I’ve seen an expectation check against one outside of a controller spec.

The second spec in this successful context is making sure the all method is returning a list of all menu items as a hash. Here is an illustration of how I’ve written these two specs:

api12_img11

What do you think about these two specs? I’d love to hear your improvement suggestions! I’m attempting to follow Marek’s advice by allowing the data in question to be treated more like local data fixtures.

And here’s a snippet from this wiki page, I’m using as my interpretation of what he has instructed:

api12_img12

Now to see if any of these pass:

api12_img13

Questions I Have

So I was able to avoid testing the performance of a web service client, and create ‘fake data’ to feed into my test’s expectations in order to mimic to the desired behaviors these specs cover.

Here are a couple of questions I have regarding the spec as they are currently written:

  1. Is the ‘fake data’ I’ve created on lines: 23 & 51 solid coverage for the all method, or do they fall into the more to be desired category?
  2. Do I really need to keep the two response specs on lines: 25 & 53, and why or why not?
  3. Should I re-write the spec on line: 57 to have an invalid expectation instead of a valid one? I need to think about the difference (if any) of writing with an understanding that the expectation is expected to be invalid in the context of an unsuccessful transaction.

Stay tuned…

Advertisements

Categories: Newbie, Ruby on rails

Tags: , ,

2 replies

  1. As far as I can tell, with your latest tests you don’t actually seem to be testing your application code?
    A good unit test should usually comprise of 4 phases: setup, exercise, verify & teardown. In your example, it appears as though you have set up the test but are not exercising the method (#all) for the object under test. (In fact, your tests are never going to fail).
    I think the expectation you meant to set was something like:
    expect(MenuItemsRetriever.all).to eq [menu_item1, menu_item2]
    The idea here is that when you call the #all method, it will go out and retrieve menu_items. However, rather than returning the actual API response, you will probably want to stub that out (using webmock, VCR or a fake).
    If you go down the route of testing this class as a ‘parser’ as per Marek’s suggestion, then from what I understand, you will need to verify that when calling the #all method, it will in fact return an array (assuming you receive JSON data via your API request). You can use ‘fake’ data inside the #all method (to stub out this request) and focus on testing the JSON to an array conversion.
    I’m also learning this stuff and just wanted to share my 2 cents! Keep up the good work with your blog – it’s putting my blog to shame!

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