Thursday, 2 June 2011

Defining requirements over Twitter

A short conversation over Twitter trying to explain what was meant but what is, in essence, a feature request made me realise some of the things that I feel is all to often missing from the requirements gathering, user story and acceptance criteria definition stage on software projects.

It all started with a thought I had or essentially, a potential requirement request that I tweeted:


To which one of my followers, the nice chap @JohnNor responded:


Which he was right to question, my original request suffered from a lot of ambiguity as to what I actually meant. So I attempted to clarify:

@JohnNor Although there's a reason not allow HTML </a> tags (some potential for xss issues) but can't see why not with something like BBcode

Which I thought was a better description. It supplies a couple of testable conditions or just about but as yet and noted a potential risk, but it turns out I hadn't successfully explained it to John yet (possibly because he doesn't have the 'domain knowledge' I have).

@sean_robbins I'm confused. What wld tweet w/ "hyperlink" look like? (I always thought web links were all hyperlinks anyway. Web=hypertext?)

John is spot on here, tweets do contain hyperlinks - of course they do - but what I meant was to hide the actual link in code and have only some descriptive text. I attempted to explain again:

@johnnor Yeah, badly phrased on my part. The key thing would not be tweet with link but |this bit| or even all of it just is a link

@JohnNor So no need for shortened link because the words themselves are the link so the url takes none of the 140 characters.

This time John was able to show his understanding to me by repeating and clarifying what I was trying to say:

@sean_robbins Oh I think I see. You would type [link=httptheverylonglinkURLindeed]LINK![/link] and Twitter would understand the code [link]?

So we got there; within the confines of a few 140 character tweets, we were able to reach a common understanding of what I was asking for. It would have been easy to take as read that all I wanted were 'hyperlinks' and point out that (duh!) - Tweets contain hyperlinks all the time and the requirement had been met.

I found it interesting because I had only recently been thinking that on software projects it can be too easy to game ourselves into thinking that our goal is to 'gather all the requirements' or to 'populate the product backlog' when actually our goal is to draw information out from our customers, understand what they need, signify that understanding to them and agree what we can actually deliver and when.

Saturday, 18 September 2010

Testing JSON integrations with Cucumber, jsonpath and Watir.

I suspected/ hoped that there must be a way to test outputs in JSON using Cucumber and Ruby without having to convert the JSON into XML and then parsing it using XPath. Seemed like an awful lot of effort to do something that feels like it should be quite simple.

I have managed to find what I believe to be a better way of doing this using the jsonpath gem.

I've been particualrly interested in this as a way to get automated tests described in Cucumber to be able make changes, perhaps at the GUI level, and then check that the JSON outputs are correct. I've basically been looking for a way to create acceptance tests that can test either the GUI, the JSON APIs or both of these for non-Ruby-on-Rails applications.

For example, assumming I wanted to test that the Twitter JSON API was updating with my most recent tweet, then I might start with a feature like:

Feature: JSON API updates with my Twitter Status

In order to be able to check my Twitter status
As a Twitter JSON API user
I want to be able to find my most recent status message

Scenario: Check my updated status on Twitter JSON API

Given that I have a Twitter account
And I update my Twitter status
When I query the Twitter JSON API
Then I should be able to find my most recent status update

Then the following is an example of what my step definitions using JSONPath might look like. Assuming that Ruby, Cucumber and Rspec already installed, the following gems would be needed to get this to work -

gem install json
gem install jsonpath

As I'm using watir-webdriver to drive the browser, then I would also need to install (these are purely for the browser tests and nothing to do with the JSON):

gem install selenium-webdriver
gem install watir-webdriver

Then the code to update my Twitter status through the browser and then check that this is updated could look something like (excepting a couple of annotations in the notes):

require 'rubygems'
require 'json'
require 'net/http'
require 'spec'
require 'jsonpath'
require 'watir-webdriver'

def twitter_json_api(twitter_name, count)
base_url = "http://api.twitter.com"

url = "#{base_url}/status/user_timeline/#{twitter_name}.json?count=#{count}"

response = Net::HTTP.get_response(URI.parse(url))

data = response.body

# Potential gotcha next. Much of the advice for the json
# gem says that it returns the JSON in a hash
# but when the JSON is an array, it is returned
# as an array and not a hash. You just need
# to know which you will be dealing with.

@result = JSON.parse(data)

return @result

end


Given /^that I have a Twitter account$/ do

@twitter_name = "a_valid_twitter_name"

@twitter_password = "a_valid_password"

end

Given /^I update my Twitter status$/ do

browser = Watir::Browser.new(:firefox)
browser.goto("http://www.twitter.com")
browser.span(:xpath, "//span[.='Sign in']").click
browser.text_field(:id, "username").set(@twitter_name)
browser.text_field(:id, "password").set(@twitter_password)
browser.button(:id, "signin_submit").click

@content = "Tweet tweet tweety tweet twoo"

browser.text_field(:id, "status").set(@content)
browser.link(:id, "tweeting_button").click

sleep(20)
#This is potential weakness that is worth consideration.
#The Twitter API doesn't update as fast as the script runs.

end

When /^I query the Twitter JSON API$/ do

#Passing a count of 1 to the API ensures I only get the most recent tweet.
@count = "1"

twitter_json_api(@twitter_name, @count)

end

Then /^I should be able to find my current status$/ do

JsonPath.new('$.text').on(@result[0]).to_a.should== @content

end

I thought this might of use/ interest to others so I dusted off my blogging shoes.

References:
Yahoo Developer Network: Parse JSON using Ruby
http://goessner.net/articles/JsonPath/
joshbuddy's jsonpath