Test JSON with Cucumber


#1

Hi Folks -

I’m hoping someone has come before me in trying to do this. I want to
use Cucumber to acceptance-test my JSON output. So far all I can do is
validate that the JSON is valid, with this step:

Then /^I should get valid JSON$/ do
assert_nothing_raised do
ActiveSupport::JSON.decode(@response.body)
end

What I’d really like to do is be able to drill down into the JSON
looking for the presence of certain elements in their correct places.
For example, if my JSON is {“foo”:{“bar”:“baz”}} and parses out to
{‘foo’ => {‘bar’ => ‘baz’}} then I want to be able to test that
[‘foo’][‘bar’] gives me ‘baz’, or at least that [‘foo’][‘bar’] exists.
Unfortunately I’m not sure how to go about writing step definitions to
do anything like this, since I haven’t yet figured out a way to take a
regular expression or string and inspect a hash with it.

Anyone have any ideas? I could really use a brain-kick here.

Thanks…


Bill K.

http://bkocik.net


#2

Bill K. wrote:

Thanks…

Well… IIRC ActiveSupport::JSON.decode will return a ruby hash of the
JSON, correct? So you should be able to make expectations on it just
like a regular hash object.

json = ActiveSupport::JSON.decode(@response.body)
json[‘foo’][‘bar’].should == ‘baz’.

Does that help or am I missing something about your question?

-Ben


#3

On Mon, May 11, 2009 at 4:32 PM, Ben M. removed_email_address@domain.invalid wrote:

Well… IIRC ActiveSupport::JSON.decode will return a ruby hash of the JSON,
correct? So you should be able to make expectations on it just like a
regular hash object.

You’re absolutely correct - I think I did a poor job of asking my
question. Maybe a more concrete example would help. Suppose I have
this JSON:

response:{code:‘200’,requestId:‘1234’}

I want to have a scenario like this in my Cucumber feature file:

When I go to “the statuses JSON url”
Then I should find “…” # [‘response’][‘code’]
And I should find “…” #[‘response’][‘requestId’]

With a step definition like:

Then /^I should find “([^”]*)"$/ do |the_string|
json = ActiveSupport::JSON.decode(@response.body)
assert_not_nil … #(something with the json obect and the_string)
end

I don’t know what goes in those blanks. Cucumber is going to give me a
string it found with the regex, but I don’t know what the string would
look like in my “Then I should find” line in my feature file, nor what
to do with it in my assert line in the step definition. I’m not even
sure any of this is possible.

Consider if I were dealing with XML instead of JSON - I could put an
XPath expression in my “Then I should find” line, and in my step
definition I could search the XML with the given XPath expression
using hpricot or something. With JSON and it’s resultant hash, I have
no idea where to start…


Bill K.

http://bkocik.net


#4

On Mon, May 11, 2009 at 5:31 PM, Bill K. removed_email_address@domain.invalid wrote:

response:{code:‘200’,requestId:‘1234’}
json = ActiveSupport::JSON.decode(@response.body)
XPath expression in my “Then I should find” line, and in my step
definition I could search the XML with the given XPath expression
using hpricot or something. With JSON and it’s resultant hash, I have
no idea where to start…

Another options is to call #to_xml on the JSON hash returned by
#decode, and then use XPath since you seem to already know it,


Bill K.

http://bkocik.net


rspec-users mailing list
removed_email_address@domain.invalid
http://rubyforge.org/mailman/listinfo/rspec-users


Zach D.
http://www.continuousthinking.com (personal)
http://www.mutuallyhuman.com (hire me)
@zachdennis (twitter)


#5

On Monday 11 May 2009, Bill K. wrote:

assert_not_nil … #(something with the json obect and
the_string) end

Do you want to cherry-pick individual pieces from the JSON, i.e. you
don’t care about the exact response as long as the parts you’re looking
for are there? Or would it be okay to check against a known good
response?

The latter case is easier. In the former case, how about a matcher that
checks the actual response is a superset of the expected response?

[…]

Consider if I were dealing with XML instead of JSON - I could put an
XPath expression in my “Then I should find” line, and in my step
definition I could search the XML with the given XPath expression
using hpricot or something. With JSON and it’s resultant hash, I have
no idea where to start…

There’s JSONPath, but I don’t think a Ruby implementation exists. If you
always have “definite” paths without wildcards and recursion(?) then you
might be able to do with some simple code like this

When I go to “the statuses JSON url”
Then I should find “response.code”

Then /^I should find “([^”]*)"$/ do |the_string|
json = ActiveSupport::JSON.decode(@response.body)
obj = traverse(json, the_string)
assert_not_nil obj
end

def traverse(json, path)
path.split(’.’).inject(json) do |value, selector|
value = value[selector]
end
rescue
nil
end

Michael


Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/


#6

Hi, I have a question about writing scenarios in cucumber that include a
JSON.
I have the following scenario in cucumber:

Scenario Outline:
Given I send and accept JSON
And I send a POST request to with the following:
“”"
{
“field1”:“text”,
“emails”:[
{
“work”:“removed_email_address@domain.invalid”,
“private”:“removed_email_address@domain.invalid”,
},
]
}
“”"
Then The response status should be “200”

Examples:
| path |
| /req |

I want the JSON to be in the examples, so that I can run the scenario
several times with different JSONs and verify that I get the correct
response status.
I want the scenario to look something like this:

Scenario Outline:
Given I send and accept JSON
And I send a POST request to with the following:
“”"

“”"
Then The response status should be “200”

how do I add the JSON to the examples?


#7

ooh - I love this solution. The downsides that immediately come to
mind are that I’d be putting XPath expressions in my acceptance tests
which aren’t necessarily readable, but since I’m the only one who has
to read them that’s alright, and that I have to parse JSON into a
hash, convert the hash to XML, and then parse that XML again with
Nokogiri or something, but assuming that the converters I’m using are
well-tested and predictable, that’s an acceptable thing to me.

The upside is that I can query my JSON with arbitrary depth and
precision using XPath. Awesome.

I love having access to groups of people who are smarter than me.
Thanks for everyone’s suggestions…

On Mon, May 11, 2009 at 6:42 PM, Zach D. removed_email_address@domain.invalid
wrote:

Another options is to call #to_xml on the JSON hash returned by
#decode, and then use XPath since you seem to already know it,


Bill K.

http://bkocik.net