Unit Testing CouchDB Views with Couch Potato
Friday, October 30th, 2009 by Alexander LangI just released Couch Potato 0.2.14 and amongst other things it has a new feature i think is pretty neat: you can unit test your (JavaScript) views using RSpec and Ruby.
You can declare a view in Couch Potato like this:
class Comment property :post_id view :by_post_id, :key => :post_id end
This will generate a pair of map/reduce function and push them to Couch Potato. The map function looks something like this:
function(doc) {
if(doc.ruby_class == 'Comment') {
emit(doc.post_id, 1);
}
}
And here’s a unit test for that function:
describe Comment, 'by_post_id' do
it "should map to the post_id" do
Comment.by_post_id.should map({:ruby_class => 'Comment', :post_id => 3}).to([3, null])
end
end
As you can see all you have to do is pass a Ruby Hash that looks like your CouchDB document and the expected results. You can also pass in multiple results if you expect your map function to emit multiple key/value pairs.
Testing a reduce function works the same way:
describe Comment, 'by_post_id' do
it "should reduce to the number of comments" do
Comment.by_post_id.should reduce([], [1, 1, 1]).to(3)
end
end
For testing re-reducing you simply call .should rereduce(...).to(...).
How it works
So how come you can test JavaScript functions in pure Ruby? Well, by stealing other people’s tricks. I recently contributed a few patches to mustache.js which is a new templating library ported to JavaScript by @janl. It has a test runner currently implemented in Ruby which generates JavaScript code on the fly, runs it using Spidermonkey and reads back the results. I have added a few steps to this process:
- A custom RSpec matcher collects the map function, a Ruby Hash representing the input and the expected output
- The input is converted to JavaScript using the JSON gem
- JavaScript code is generated that runs the document through the map function and prints the resulting JSON.
- The Ruby code runs spidermonkey, collects the output and parses it back to Ruby using again the JSON gem
- The results are compared to the expected values.
You can see how it works by looking at the code for the RSpec matchers.
I think this addition lowers the barrier to test your views quite a bit. Although I’m usually not a big fan of “one language to rule them all” and love writing JavaScript, being able to write all the necessary tests in Ruby when working on a Ruby project makes things way easier.



