{"id":158,"date":"2009-07-25T16:42:42","date_gmt":"2009-07-25T23:42:42","guid":{"rendered":"http:\/\/blog.monnet-usa.com\/?p=158"},"modified":"2009-07-25T16:42:42","modified_gmt":"2009-07-25T23:42:42","slug":"green-behavior-driven-development-with-cucumber","status":"publish","type":"post","link":"https:\/\/blog.monnet-usa.com\/?p=158","title":{"rendered":"Green Behavior-Driven Development With Cucumber"},"content":{"rendered":"<h3>DDT \/ Development-Driven Tests <\/h3>\n<p>\n\tFor the last several years I have been generalizing the use of automated unit tests on my team (at work) as part of the development process for our C#-based enterprise services and business applications. Circa 2005, I was using NUnit and NAnt and Cruise Control to implement continuous integrations builds. Then as we implemented Team Foundation Server, we switched to MS Test. We created unit tests focused on specific classes as well as integration tests focused on interactions involving multiple classes. I have usually tried to strike the balance on not creating test for the sake of test but mostly to test complex logic and ensure key enterprise services would work reliably. Automated tests have been part of our coding process but not upfront as the Test-Driven Development practitioners would propose. I have been resistant to TDD for a couple reasons:<\/p>\n<ul>\n<li>Early on, developers need to focus on understanding the target functionality<\/li>\n<li>Our lifecycle includes some up-front time-boxed design focused on components and their interactions<\/li>\n<li>It is easy to fall deep in the rabit hole of creating too many detailed tests with all their associated fixture<\/li>\n<li>If the depth and breadth of tests are inconsistent the cost of the development phase can quickly go up<\/li>\n<\/ul>\n<p>Our practice is really DDT i.e. Development-Driven Tests, as opposed to TDD (Test-Driven Development).\n\t<\/p>\n<h3>The Missing Ingredient In The Recipe<\/h3>\n<p>\n\tSo an ingredient is missing: how to get developers to absorb the new functionality in palatable chunks while yet conjuring and capture the interesting scenarios that might influence the structure of the code.\n\t<\/p>\n<h3>Focus on Behavior And Acceptance Is Key<\/h3>\n<p>\n\tMy outside-work interests in Ruby, Web Frameworks, and Agile approaches recently brought me to dig into the different types of testing frameworks associated with Rails projects such as:\n\t<\/p>\n<ul>\n<li><a href=\"http:\/\/rspec.info\/\">RSpec<\/a> &#8211; the father of Ruby-based BDD frameworks<\/li>\n<li><a href=\"http:\/\/www.thoughtbot.com\/projects\/shoulda\/\" >Shoulda<\/a> &#8211; alternative to RSpec trying to make the syntax a bit easier to read<\/li>\n<li><a href=\"http:\/\/cukes.info\/\">Cucumber<\/a> &#8211; set the tone by focusing the author on the <a href=\"http:\/\/wiki.github.com\/aslakhellesoy\/cucumber\/given-when-then\">&#8220;Given-When-Then&#8221;<\/a> structure<\/li>\n<\/ul>\n<p>\nThere are probably other frameworks but so far I have only looked into these three.<br \/>\nThese frameworks aim at raising the level of abstraction above the traditional &#8220;x-unit&#8221;-style unit tests which are typically focused on defining test methods containing specific code-level assertions such as:\n\t<\/p>\n<ol>\n<li>TestUnit Example:<\/li>\n<pre class=\"brush: ruby\">\r\nclass MyTest < Test::Unit::TestCase\r\n  def do_some_work\r\n    # ...\r\n    assert_equal(\"OK\", result)\r\n  end\r\nend\r\n<\/pre>\n<li>Rspec Example:<\/li>\n<pre class=\"brush: ruby\">\r\nrequire 'rubygems'\r\nrequire 'spec'\r\n\r\ndescribe \"Skills Tracking\" do\r\n\tit \"should track skills for a given user\" do\r\n\tend\r\nend\r\n<\/pre>\n<p>Running the spec produces:<br \/>\n<img decoding=\"async\" src=\".\/wp-content\/uploads\/2009\/07\/RSpec-Demo.png\"\/><\/p>\n<\/ol>\n<p>These frameworks are very convenient to build acceptance either ahead or during development but they still set the expectation that you are writing at least some minimal code. You will also notice that even though help create what is called \"syntactic sugar\" to help with readability, authoring a spec requires that you at least know quite a bit the syntax. What if the abstraction level could be raised one more level and guide you through the BDD process?<\/p>\n<h3>Adding Cucumber To The Recipe<\/h3>\n<p>\n\tWell, search no more! Cucumber help focus the author on the key tenet of BDD:\n\t<\/p>\n<ol>\n<li>Define each business <a href=\"#\">Feature<\/a> - using the syntax:<\/li>\n<ul>\n<li><a href=\"#\">In order<\/a> to...<\/li>\n<li><a href=\"#\">As a<\/a>...<\/li>\n<li><a href=\"#\">I want<\/a>...<\/li>\n<\/ul>\n<pre class=\"brush: plain\">\r\nFeature: Skills Tracking\r\n  In order to manage my skills\r\n  As a person continuously developing skills  \r\n  I want to be track my skills\r\n<\/pre>\n<li>Define multiple <a href=\"#\">Scenario<\/a>s where a <a href=\"#\">feature<\/a> can be exercised - using the syntax:<\/li>\n<ul>\n<li><a href=\"#\">Given<\/a><\/li>\n<li><a href=\"#\">When<\/a><\/li>\n<li><a href=\"#\">Then<\/a><\/li>\n<\/ul>\n<pre class=\"brush: plain\">\r\nScenario: Track New Skill\r\n  Given a new skill \r\n  When I define a new skill\r\n  Then the new skill will be tracked\r\n \r\nScenario: Update Skill Proficiency\r\n  Given an existing skill \r\n  When I have increased my proficiency level with that skill\r\n  Then the skill proficiency level will be updated\r\n<\/pre>\n<\/ol>\n<p>\nNotice that I have not used any code and very minimal syntax. The approach also leads you to define scenarios as you specify your feature. I don't need to think about code quite yet.\n<\/p>\n<h3>Tasting The Cucumber<\/h3>\n<p>\nSo let's see what minimal infrastructure is needed. I am assuming you have Ruby. If not, check my post titled <a href=\"https:\/\/blog.monnet-usa.com\/?page_id=48\">Getting Started With Ruby And Rails<\/a>.\tTo keep things to a minimum, I am going to show you how to create your features with only Ruby (as opposed to depending on the whole Rails stack).\n\t<\/p>\n<ol>\n<li>Install the cucumber gem<\/li>\n<pre class=\"brush: ruby\">\r\ngem install cucumber\r\n<\/pre>\n<li>Create a project folder (e.g. \"<b>Cuke<\/b>\")<\/li>\n<li>Create a file in <b>Cuke<\/b>, name it <b>rakefile<\/b> and edit it to enter the following content:<\/li>\n<pre class=\"brush: ruby\">\r\nrequire 'rake'\r\nrequire 'rake\/testtask'\r\nrequire 'rake\/rdoctask'\r\n\r\nrequire 'cucumber\/rake\/task'\r\n \r\nCucumber::Rake::Task.new do |t|\r\n  t.cucumber_opts = \"--format pretty\"\r\nend\r\n<\/pre>\n<li>Create a file in <b>Cuke<\/b>, name it <b>cucumber.yml<\/b> and edit it to enter the following content:<\/li>\n<pre class=\"brush: ruby\">\r\nautotest: -r features --format pretty --color\r\n<\/pre>\n<li>Create a <b>lib<\/b> folder below <b>Cuke<\/b><\/li>\n<li>Create a <b>tasks<\/b> folder below <b>Cukelib<\/b><\/li>\n<li>Create a file in Cukelibtasks, name it <b>cucumber.rake<\/b> and edit it to enter the following content:<\/li>\n<pre class=\"brush: ruby\">\r\nbegin\r\n  require 'cucumber\/rake\/task'\r\n\r\n  Cucumber::Rake::Task.new(:features) do |t|\r\n    t.fork = true\r\n    t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]\r\n  end\r\n  task :features => 'db:test:prepare'\r\nrescue LoadError\r\n  desc 'Cucumber rake task not available'\r\n  task :features do\r\n    abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'\r\n  end\r\nend\r\n<\/pre>\n<li>Create a <b>features<\/b> folder below <b>Cuke<\/b><\/li>\n<li>Create a file in Cuke, name it <b>testcuke.feature<\/b> and edit it to enter the following content:<\/li>\n<pre class=\"brush: plain\">\r\nFeature: Skills Tracking\r\n  In order to manage my skills\r\n  As a person continuously developing skills  \r\n  I want to be track my skills\r\n<\/pre>\n<li>Open a command window on our <b>Cuke<\/b> folder and let's run Cucumber<\/li>\n<pre class=\"brush: bash\">\r\ncucumber features\/testcuke.feature\r\n<\/pre>\n<p>The result is:<br \/>\n<img decoding=\"async\" src=\".\/wp-content\/uploads\/2009\/07\/Cukember-Feature-Test.Png\"\/><vr\/><\/p>\n<li>Let's add a scenario to the feature:<\/li>\n<pre class=\"brush: plain\">\r\nScenario: Track New Skill\r\n  Given a new skill \r\n  When I define a new skill\r\n  Then the new skill will be tracked\r\n<\/pre>\n<li>Let' re-run Cucumber<\/li>\n<pre class=\"brush: bash\">\r\ncucumber features\/testcuke.feature\r\n<\/pre>\n<p>The result is:<br \/>\n<img decoding=\"async\" src=\".\/wp-content\/uploads\/2009\/07\/Cukember-Scenario-Test.Png\"\/><vr\/><br \/>\nCucumber identified the steps of the scenario and colored them amber to indicate that they are not implemented yet. So let's tackle one step.<\/p>\n<li>Create a <b>step_definitions<\/b> folder below <b>Cuke<\/b><\/li>\n<li>Create a file in <b>Cukestep_definitions<\/b>, name it <b>skill_step.rb<\/b> and edit it to enter the following content based on the template suggested by Cucumber:<\/li>\n<pre class=\"brush: plain\">\r\nGiven \/^a new skill$\/ do\r\n  pending\r\nend<\/pre>\n<li>Let' re-run Cucumber<\/li>\n<pre class=\"brush: bash\">\r\ncucumber features\/testcuke.feature\r\n<\/pre>\n<p>The result is:<br \/>\n<img decoding=\"async\" src=\".\/wp-content\/uploads\/2009\/07\/Cucumber-Step-Test-1.png\"\/><br \/>\nTo make the test pass we would need to fully implement the step.<\/p>\n<\/ol>\n<h3>Incremental BDD<\/h3>\n<p>\nSo far, everytime we have refined the feature, its scenarios and steps, we have re-run cucumber. What if Cucumber could run as soon as a change has been made (i.e. a file has been updated).<br \/>\nEnter <a href=\"\">autotest<\/a>, a <b>\"file-watcher\"<\/b> which will trigger a new run of Cucumber.\n\t<\/p>\n<ol>\n<li>Install the ZenTest gem<\/li>\n<pre class=\"brush: ruby\">\r\ngem install cucumber\r\n<\/pre>\n<li>Set the following environment variables in your command line session<\/li>\n<pre class=\"brush: bash\">\r\nSET AUTOFEATURE=true\r\nSET HOME=.\r\n<\/pre>\n<li>Run autotest<\/li>\n<pre class=\"brush: bash\">\r\nautotest\r\n<\/pre>\n<\/ol>\n<p>\nNow when you make a change to any file, you will see autotest run Cucumber.\n<\/p>\n<h3>So What?<\/h3>\n<p>\nLooking back at TDD (or DDT!) practices, it is clear that the focus of testing is more on code artifacts than on <b>functional features<\/b>.<br \/>\nBehavior-Driven Development\tcan help a development team absorb and <b>distill business requirement<\/b> into acceptance test scenarios from which automated tests can be derived. <br \/>\nEven if you are not using Ruby or Rails as your development platform, Cucumber and Ruby can still play a role during the <b>design phase<\/b>. And you can, over time, introduce the use of Ruby to create <b>integration test<\/b> with non-Ruby components either through web services, databases or web clients.<br \/>\nIf your core platform is .NET and you are considering building rich clients with Silverlight, you should also consider <a href=\"http:\/\/www.ironruby.net\/\">IronRuby<\/a>. In that scenario, Cucumber can directly be leveraged with IronRuby. <br \/>\nOver time, I am envisioning the following for my team:\n\t<\/p>\n<ul>\n<li>We start leveraging Cucumber to map some of the key functional requirements into features (but from a developer's standpoint)<\/li>\n<li>When ready we derive high-level integration tests using IronRuby<\/li>\n<li>We create C#-based unit tests<\/li>\n<li>We then combine IronRuby integration tests with lower-level unit test-level harnesses<\/li>\n<\/ul>\n<p>\nI am clearly planning to further develop my knowledge and experience with BDD through Cucumber.\n<\/p>\n<p><\/p>\n<hr\/>\n<h3>References and Resources<\/h3>\n<h5>Sites:<\/h5>\n<ol>\n<li><a href=\"http:\/\/behaviour-driven.org\/\">BDD<\/a> - Behavior-Driven Development<\/li>\n<li><a href=\"http:\/\/dannorth.net\/introducing-bdd\">Dan North<\/a> first article on BDD<\/li>\n<li><a href=\"http:\/\/rspec.info\/\">RSpec<\/a> - the father of Ruby-based BDD frameworks<\/li>\n<li><a href=\"http:\/\/www.thoughtbot.com\/projects\/shoulda\/\" >Shoulda<\/a> - alternative to RSpec trying to make the syntax a bit easier to read<\/li>\n<li><a href=\"http:\/\/cukes.info\/\">Cucumber<\/a> - set the tone by focusing the author on the <a href=\"http:\/\/wiki.github.com\/aslakhellesoy\/cucumber\/given-when-then\">\"Given-When-Then\"<\/a> structure<\/li>\n<li><a href=\"http:\/\/www.pragprog.com\/titles\/achbd\/the-rspec-book\">Outside-In Development with Cucumber<\/a>: Ben Mabey<\/li>\n<\/ol>\n<h5>Books:<\/h5>\n<ol>\n<li><a href=\"http:\/\/www.pragprog.com\/titles\/achbd\/the-rspec-book\">The RSpec Book<\/a>: Behaviour Driven Development with RSpec, Cucumber, and Friends<\/li>\n<\/ol>\n<h5>Videos:<\/h5>\n<ol>\n<li><a href=\"http:\/\/mwrc2009.confreaks.com\/14-mar-2009-15-00-bdd-with-cucumber-ben-mabey.html\">Outside-In Development with Cucumber<\/a>: Video of Ben Mabey's presentation<\/li>\n<li><a href=\"http:\/\/video.google.com\/videoplay?docid=8135690990081075324\">Beyond Test Driven Development: Behaviour Driven Development<\/a> - Dave Astels<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>DDT \/ Development-Driven Tests For the last several years I have been generalizing the use of automated unit tests on my team (at work) as part of the development process for our C#-based enterprise services and business applications. Circa 2005, I was using NUnit and NAnt and Cruise Control to implement continuous integrations builds. Then [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21,3],"tags":[55,56],"class_list":["post-158","post","type-post","status-publish","format-standard","hentry","category-bdd","category-ruby","tag-bdd","tag-ruby"],"_links":{"self":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/158","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=158"}],"version-history":[{"count":7,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/158\/revisions"}],"predecessor-version":[{"id":165,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/158\/revisions\/165"}],"wp:attachment":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}