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
Added almost 2 years ago by Devo_normal gbuesing