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:
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:
Here’s a snippet from a blog post by Nick Gauthier:
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.
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:
Lets work on the first spec inside our
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.
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:
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:
Now to see if any of these pass:
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:
Is the ‘fake data’ I’ve created on lines: 23 & 51 solid coverage for the
allmethod, or do they fall into the more to be desired category?
- Do I really need to keep the two response specs on lines: 25 & 53, and why or why not?
- 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.