document.write('<link rel="stylesheet" href="http://flowcoder.com/stylesheets/pygment_trac.css" />');
document.write('<link rel="stylesheet" href="http://flowcoder.com/stylesheets/embed.css" />');
document.write('<div class="flowcoder_post flowcoder_clearfix">');
document.write('<div class="flowcoder_posttitle"><a href=\"http://flowcoder.com/184\">Testing CouchDB view functions in Ruby with Johnson<\/a></div>');
document.write('<div class="flowcoder_postbody flowcoder_syntax"><div class=\"highlight\"><pre><span class=\"c1\"># When CouchDB view functions get complex, it&#39;s nice to be able to unit test them.<\/span>\n<span class=\"c1\"># When your development dataset is large, and views take some time to build, better<\/span>\n<span class=\"c1\"># to find bugs via unit tests over having to wait for a view build to see if things<\/span>\n<span class=\"c1\"># are working correctly.<\/span>\n\n<span class=\"c1\"># This implementation uses Johnson for executing Javascript -- see the evaluate_map method<\/span>\n<span class=\"c1\"># at the end of this file. Note that we can define the emit and log functions as Ruby Proc <\/span>\n<span class=\"c1\"># objects and have them work in the Javascript context. Pretty cool.<\/span>\n\n<span class=\"c1\"># I think it would be possible to test show and list functions as well, using a similar<\/span>\n<span class=\"c1\"># technique to mock out the getRow() and send() functions.<\/span>\n<span class=\"nb\">require<\/span> <span class=\"s1\">&#39;rubygems&#39;<\/span>\n<span class=\"nb\">require<\/span> <span class=\"s2\">&quot;johnson&quot;<\/span>\n<span class=\"nb\">require<\/span> <span class=\"s2\">&quot;json&quot;<\/span>\n<span class=\"nb\">require<\/span> <span class=\"s2\">&quot;test/unit&quot;<\/span>\n\n<span class=\"c1\"># Johnson monkeypatch, so that assert_equal works as expected with array values<\/span>\n<span class=\"k\">class<\/span> <span class=\"nc\">Johnson<\/span><span class=\"o\">::<\/span><span class=\"no\">SpiderMonkey<\/span><span class=\"o\">::<\/span><span class=\"no\">RubyLandProxy<\/span>\n  <span class=\"k\">def<\/span> <span class=\"nf\">==<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">case<\/span> <span class=\"n\">other<\/span>\n    <span class=\"k\">when<\/span> <span class=\"nb\">Array<\/span>\n      <span class=\"nb\">to_a<\/span> <span class=\"o\">==<\/span> <span class=\"n\">other<\/span>\n    <span class=\"k\">else<\/span>\n      <span class=\"k\">super<\/span>\n    <span class=\"k\">end<\/span>\n  <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">TestViews<\/span> <span class=\"o\">&lt;<\/span> <span class=\"no\">Test<\/span><span class=\"o\">::<\/span><span class=\"no\">Unit<\/span><span class=\"o\">::<\/span><span class=\"no\">TestCase<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">setup<\/span>\n    <span class=\"c1\"># Set the design doc in an instance variable. In practice, you&#39;ll want to get the <\/span>\n    <span class=\"c1\"># design doc from the server using your preferred HTTP client, ex:<\/span>\n    <span class=\"c1\"># <\/span>\n    <span class=\"c1\">#   @ddoc = JSON.parse RestClient.get(&#39;localhost:5984/mydb/_design/myapp&#39;)<\/span>\n    <span class=\"c1\">#<\/span>\n    <span class=\"c1\"># If you&#39;re getting the same ddoc again and again for each test, you can store it in a<\/span>\n    <span class=\"c1\"># class variable or constant on test suite startup, thus avoiding the overhead of <\/span>\n    <span class=\"c1\"># HTTP and JSON parsing of the ddoc for each test.<\/span>\n    <span class=\"vi\">@ddoc<\/span> <span class=\"o\">=<\/span> <span class=\"no\">JSON<\/span><span class=\"o\">.<\/span><span class=\"n\">parse<\/span><span class=\"p\">(<\/span><span class=\"o\">&lt;&lt;-<\/span><span class=\"no\">EOV<\/span><span class=\"p\">)<\/span>\n<span class=\"sh\">      {<\/span>\n<span class=\"sh\">        &quot;_id&quot;: &quot;_design/myapp&quot;,<\/span>\n<span class=\"sh\">        &quot;views&quot;: {<\/span>\n<span class=\"sh\">          &quot;by_city&quot;: {<\/span>\n<span class=\"sh\">            &quot;map&quot;: &quot;function(doc) { emit([doc.city, doc.name], doc); }&quot;<\/span>\n<span class=\"sh\">          }<\/span>\n<span class=\"sh\">        }<\/span>\n<span class=\"sh\">      }<\/span>\n<span class=\"no\">    EOV<\/span>\n  <span class=\"k\">end<\/span>\n\n  <span class=\"k\">def<\/span> <span class=\"nf\">test_by_city<\/span>\n    <span class=\"n\">mapfun<\/span> <span class=\"o\">=<\/span> <span class=\"vi\">@ddoc<\/span><span class=\"o\">[<\/span><span class=\"s1\">&#39;views&#39;<\/span><span class=\"o\">][<\/span><span class=\"s1\">&#39;by_city&#39;<\/span><span class=\"o\">][<\/span><span class=\"s1\">&#39;map&#39;<\/span><span class=\"o\">]<\/span>\n    <span class=\"n\">doc<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"s2\">&quot;name&quot;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"s2\">&quot;Geoff&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;city&quot;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"s2\">&quot;Chicago&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;state&quot;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"s2\">&quot;IL&quot;<\/span><span class=\"p\">}<\/span>\n    \n    <span class=\"n\">rows<\/span> <span class=\"o\">=<\/span> <span class=\"n\">evaluate_map<\/span><span class=\"p\">(<\/span><span class=\"n\">mapfun<\/span><span class=\"p\">,<\/span> <span class=\"n\">doc<\/span><span class=\"p\">)<\/span><span class=\"o\">[<\/span><span class=\"s1\">&#39;rows&#39;<\/span><span class=\"o\">]<\/span>\n    \n    <span class=\"n\">assert_equal<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">rows<\/span><span class=\"o\">.<\/span><span class=\"n\">size<\/span>\n    <span class=\"n\">assert_equal<\/span> <span class=\"o\">[<\/span><span class=\"s2\">&quot;Chicago&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Geoff&quot;<\/span><span class=\"o\">]<\/span><span class=\"p\">,<\/span> <span class=\"n\">rows<\/span><span class=\"o\">.<\/span><span class=\"n\">first<\/span><span class=\"o\">[<\/span><span class=\"s1\">&#39;key&#39;<\/span><span class=\"o\">]<\/span>\n    <span class=\"n\">assert_equal<\/span> <span class=\"n\">doc<\/span><span class=\"p\">,<\/span> <span class=\"n\">rows<\/span><span class=\"o\">.<\/span><span class=\"n\">first<\/span><span class=\"o\">[<\/span><span class=\"s1\">&#39;value&#39;<\/span><span class=\"o\">]<\/span>\n  <span class=\"k\">end<\/span>\n  \n\n  <span class=\"kp\">private<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">evaluate_map<\/span><span class=\"p\">(<\/span><span class=\"n\">fun<\/span><span class=\"p\">,<\/span> <span class=\"n\">doc<\/span><span class=\"p\">)<\/span>\n      <span class=\"n\">rows<\/span><span class=\"p\">,<\/span> <span class=\"n\">log<\/span> <span class=\"o\">=<\/span> <span class=\"o\">[]<\/span><span class=\"p\">,<\/span> <span class=\"o\">[]<\/span>\n      <span class=\"n\">emitfun<\/span> <span class=\"o\">=<\/span> <span class=\"no\">Proc<\/span><span class=\"o\">.<\/span><span class=\"n\">new<\/span> <span class=\"p\">{<\/span><span class=\"o\">|<\/span><span class=\"n\">k<\/span><span class=\"p\">,<\/span> <span class=\"n\">v<\/span><span class=\"o\">|<\/span> <span class=\"n\">rows<\/span> <span class=\"o\">&lt;&lt;<\/span> <span class=\"p\">{<\/span><span class=\"s2\">&quot;key&quot;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"n\">k<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;value&quot;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"n\">v<\/span><span class=\"p\">}}<\/span>\n      <span class=\"n\">logfun<\/span> <span class=\"o\">=<\/span> <span class=\"no\">Proc<\/span><span class=\"o\">.<\/span><span class=\"n\">new<\/span> <span class=\"p\">{<\/span><span class=\"o\">|<\/span><span class=\"n\">m<\/span><span class=\"o\">|<\/span> <span class=\"n\">log<\/span> <span class=\"o\">&lt;&lt;<\/span> <span class=\"n\">m<\/span><span class=\"p\">}<\/span>\n      <span class=\"n\">map<\/span> <span class=\"o\">=<\/span> <span class=\"no\">Johnson<\/span><span class=\"o\">.<\/span><span class=\"n\">evaluate<\/span><span class=\"p\">(<\/span><span class=\"n\">fun<\/span><span class=\"p\">,<\/span> <span class=\"ss\">:emit<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"n\">emitfun<\/span><span class=\"p\">,<\/span> <span class=\"ss\">:log<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"n\">logfun<\/span><span class=\"p\">)<\/span>\n      <span class=\"n\">map<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">(<\/span><span class=\"n\">doc<\/span><span class=\"p\">)<\/span>\n      <span class=\"p\">{<\/span><span class=\"s2\">&quot;rows&quot;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"n\">rows<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;log&quot;<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"n\">log<\/span><span class=\"p\">}<\/span>\n    <span class=\"k\">end<\/span>\n<span class=\"k\">end<\/span>\n<\/pre><\/div>\n</div>');
document.write('<div class="flowcoder_bottombar flowcoder_clearfix">');
document.write('<div class="flowcoder_postedby">Posted by <a href=\"http://flowcoder.com/gbuesing\">gbuesing<\/a> on <a href=\"http://flowcoder.com/\">Flowcoder<\/a></div>');
document.write('<div class="flowcoder_viewraw"><a href=\"http://flowcoder.com/184.txt\">view raw<\/a></div>');
document.write('</div></div>');
