Testing CouchDB view functions in Ruby with Johnson
Language: Ruby
# When CouchDB view functions get complex, it's nice to be able to unit test them.
# When your development dataset is large, and views take some time to build, better
# to find bugs via unit tests over having to wait for a view build to see if things
# are working correctly.
# This implementation uses Johnson for executing Javascript -- see the evaluate_map method
# at the end of this file. Note that we can define the emit and log functions as Ruby Proc
# objects and have them work in the Javascript context. Pretty cool.
# I think it would be possible to test show and list functions as well, using a similar
# technique to mock out the getRow() and send() functions.
require 'rubygems'
require "johnson"
require "json"
require "test/unit"
# Johnson monkeypatch, so that assert_equal works as expected with array values
class Johnson::SpiderMonkey::RubyLandProxy
def ==(other)
case other
when Array
to_a == other
else
super
end
end
end
class TestViews < Test::Unit::TestCase
def setup
# Set the design doc in an instance variable. In practice, you'll want to get the
# design doc from the server using your preferred HTTP client, ex:
#
# @ddoc = JSON.parse RestClient.get('localhost:5984/mydb/_design/myapp')
#
# If you're getting the same ddoc again and again for each test, you can store it in a
# class variable or constant on test suite startup, thus avoiding the overhead of
# HTTP and JSON parsing of the ddoc for each test.
@ddoc = JSON.parse(<<-EOV)
{
"_id": "_design/myapp",
"views": {
"by_city": {
"map": "function(doc) { emit([doc.city, doc.name], doc); }"
}
}
}
EOV
end
def test_by_city
mapfun = @ddoc['views']['by_city']['map']
doc = {"name" => "Geoff", "city" => "Chicago", "state" => "IL"}
rows = evaluate_map(mapfun, doc)['rows']
assert_equal 1, rows.size
assert_equal ["Chicago", "Geoff"], rows.first['key']
assert_equal doc, rows.first['value']
end
private
def evaluate_map(fun, doc)
rows, log = [], []
emitfun = Proc.new {|k, v| rows << {"key" => k, "value" => v}}
logfun = Proc.new {|m| log << m}
map = Johnson.evaluate(fun, :emit => emitfun, :log => logfun)
map.call(doc)
{"rows" => rows, "log" => log}
end
end
Reveal More

