Javascript unit testing, yes we can   e big
Upcoming SlideShare
Loading in...5
×
 

Javascript unit testing, yes we can e big

on

  • 2,790 views

 

Statistics

Views

Total Views
2,790
Views on SlideShare
2,773
Embed Views
17

Actions

Likes
3
Downloads
29
Comments
0

1 Embed 17

http://www.slideshare.net 17

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Ask everyone to introduce themselves quickly. <br />
  • Who Writes Java? Write Unit tests? <br /> Who Writes Ruby <br /> Who Writes JavaScript? Do you write unit tests? <br /> BDD? <br /> jQuery? <br /> <br />
  • <br />
  • <br />
  • John Resig Survey: http://www.slideshare.net/jeresig/understanding-javascript-testing <br /> <br /> Counter each of these!!!! <br />
  • we wrote something we otherwise would have outsourced to Flash developers-- demo method explorer <br />
  • <br />
  • <br />
  • # nested describes--- <br /> # need button to go to next fieldset <br /> it("should add &apos;next&apos; button to first fieldset", function() { <br /> expect($("form fieldset:first a").text()).to(equal, &apos;Next&apos;); <br /> }); <br /> it("should add &apos;next&apos; class to next button", function() { <br /> expect($("form fieldset:first a").hasClass(&apos;next&apos;)).to(equal, true); <br /> }); <br /> it("should add &apos;next&apos; button to second fieldset", function() { <br /> expect($("form fieldset:nth(1) a:last").text()).to(equal, &apos;Next&apos;); <br /> }); <br /> it("should not add &apos;next&apos; buttons to last fieldset", function() { <br /> expect($("form fieldset:last a").text()).to(equal, &apos;&apos;); <br /> }); <br /> <br /> # code <br /> $(&apos;fieldset:not(:last)&apos;).each(function() { $(this).append(&apos;<a>Next</a>&apos;) }); <br /> <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • ./script/generate javascript_spec wiz <br /> <br /> # create fixture <br /> <br /> <br /> <br /> <br /> <br /> <br /> # create simple test <br /> describe(&apos;initialization&apos;, function() { <br /> it("shows the first fieldset", function(){ <br /> expect($("form fieldset:first").is(&apos;:visible&apos;)).to(equal, true); <br /> }); <br /> }); <br /> # run from command line <br /> <br /> # tests that fail <br /> it("hides the second and third fieldset", function(){ <br /> expect($("form fieldset:not(:first)").is(&apos;:visible&apos;)).to(equal, false); <br /> }); <br /> <br /> # run from command line <br /> <br /> # write code in before block <br /> <br /> var wizardize = function() { <br /> $(&apos;form&apos;).each(function() { <br /> $(&apos;fieldset&apos;, this).hide(); <br /> $(&apos;fieldset:first&apos;, this).show(); <br /> }); <br /> <br />
  • mkdir demo <br /> cd demo <br /> rails demo <br /> cd demo <br /> ./script/plugin install git://github.com/relevance/blue-ridge.git <br /> ./script/generate blue_ridge <br /> <br />
  • mkdir demo <br /> cd demo <br /> rails demo <br /> cd demo <br /> ./script/plugin install git://github.com/relevance/blue-ridge.git <br /> ./script/generate blue_ridge <br /> <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

Javascript unit testing, yes we can   e big Javascript unit testing, yes we can e big Presentation Transcript

  • Test-Driven JavaScript with ScrewUnit & BlueRidge Andy Peterson Jonah Williams Carbon Five
  • Introductions
  • Carbon Five Boutique software consulting 20 people, all developers Agile development, collaboration, transparency Mix of projects: start-ups / non-profits / enterprise History of Java, but now RoR + misc.
  • Agenda JavaScript unit testing: how & why BDD, jQuery, plugins Demo TDD with a simple test Problems & lessons learned Q&A
  • Why NOT JS Unit Testing? Can’t get started We don’t; nobody else does Patterns unclear-- what does it look like Too many tools (and arch.) to choose from ... lack of tool & infrastructure support Flakey/bad experiences
  • Why JS Unit Testing? Tests => Confidence => Ambition Take on more challenging requirements More homogenous architecture (w/o Flash) Push logic into browser... scalability Refactor reliably
  • JS Testing Universe Styles of Tests: xUnit: JSUnit, QUnit, YUITest, etc. BDD: JSSpec, ScrewUnit Automation: In-browser w/ Selenium, WebDriver, JSTestDriver Out of browser: Env.js + Rhino
  • Blue Ridge Ruby on Rails plugin (therefore conventions!) Integrates ScrewUnit (BDD) and Smoke (mocking) Glue code and scripts Rhino & Env.js to run out of browser from Larry Karnowski, Runcoderun
  • BDD Language closer to user stories Popularized by RSpec in Ruby describe -- organize before / after blocks Nesting describes -- to DRY One assert should per test example
  • describe Stack do before(:each) do @stack = Stack.new @stack.push :item end describe "#peek" do it "should return the top element" do @stack.peek.should == :item end it "should not remove the top element" do @stack.peek @stack.size.should == 1 end end describe "#pop" do Stack (generated docs) it "should return the top element" do #peek @stack.pop.should == :item - should return the top element end it "should remove the top element" do - should not remove the top @stack.pop element @stack.size.should == 0 #pop end - should return the top element end end - should remove the top element
  • BDD in RSpec describe 'a man' { before { @man = Man.new :luck=>5 } describe '#decrement_luck' { it "decrements the luck field by the given amount" { @man.decrement_luck(3) @man.luck.should == 2 } } ... });
  • BDD in ScrewUnit describe('Man', function() { var man; before(function() { man = new Man({luck: 5}); }); describe('#decrement_luck', function() { it("decrements the luck field by the given amount", function() { man.decrement_luck(3); expect(man.luck()).to(equal, 2) }); }); ... });
  • Let’s See It
  • Wizard-izer (our example) Given a form comprised of fieldsets Creates a “panel” for each fieldset Hides all but the first panel Adds buttons to navigate panels etc.
  • Blue Ridge Installation http://github.com/relevance/blue-ridge/tree/master # Within a rails project > ./script/plugin install git:// github.com/relevance/blueridge.git > ./script/generate blue_ridge > ./script/generate javascript_spec wiz
  • Maven Installation http://code.google.com/p/javascript-test-maven-plugin/ <plugin> <executions><execution> <goals> <goal>javascript-test</goal> </goals> </execution></executions> <groupId>com.carbonfive.javascript-test</groupId> <artifactId>javascript-test-maven-plugin</artifactId> <version>1.0-beta1</version> <configuration> <includes> <include>src/test/javascript/suite*.html</include> </includes> </configuration> </plugin>
  • 3 Components Fixture - markup that JS requires test/javascript/widget.html Spec - tests test/javascript/specs/widget_spec.js) Code to test - independent JS <public>/javascript/widget.js
  • jQuery Functional DOM manipulation One function $: $(selector) eg. $(‘p.cls’) Chainable -- $ (‘p.cls’).addClass(‘abc’).removeClass(‘cls’).etc(...) Plugins
  • jQuery Plugin Add function to jQuery.fn.reverse() = function() { jQuery object // “this” is list of nodes Receive list of nodes $(this).each(function() { var t = $(this).text(); Do your stuff $(this).text(t); } Return “this” return this; Good tutorials online }
  • DOM cleanup Tools don’t reset your DOM automatically They are writing status back to the page (yuck!) Solution Wrap fixtures (in #fixture container) before function that restores DOM state
  • DOM cleanup fn // before(function() { $('#fixture).fixture(); }); jQuery.fn.fixture = function() { this.each(function() { if (this.original) { $(this).html(this.original); } else { this.original = $(this).html(); } }); }
  • Put CSS in Fixture Helps with debugging Use FireBug to inspect
  • Structure as a jQuery plugin jQuery is not required-- but really helps you organize code Separate document.ready() from code-- dependency injection Use as organizing principal, and dependency injection Write modular code, instead page-specific code
  • Learnings
  • Not Hard to Make JS Testing a Part of Your Process
  • Markup Design Generated in JS? On the server? Hybrid? Unit testing encourages generating more markup in JavaScript Will affect SEO and accessibility (good or bad)
  • When to test Some JS can be experimental Test-drive when you have a good sense of what he component is Testing is a refactoring tool As code gets complicated, pull into testable units
  • Don’t Be Afraid of JS Reminder wizard Method chooser demo-- data driven JS, with ajax structure
  • What to Unit Test / Limitations AJAX JavaScript Unit Testing setTimeout() setInterval() DOM Business Manipulation Logic Animations Computed sizes
  • It’s Not Browser Testing ...it’s JS unit testing Not cross-browser testing Not your production markup Functional test framework still have a place
  • Our Testing Stack Selenium Integration & Browser Testing 1/10th Controller/View Integration Tests 1/5th Javascript Unit Testing Model Unit Controller Unit 1/10th Tests Tests
  • JavaScript Testing Yes We Can! Andy Peterson Jonah Williams andy@carbonfive.com jonah@carbonfive.com skype: ndpsoft
  • Blue Ridge TODOs Run in more browsers (not just Firefox) Speed Events Driving in multiple browsers Using code served from app Shenandoah
  • Other Options ScrewUnit Server Selenium + JSUnit testswarm (?)
  • References (Bibliography) http://github.com/relevance/blue-ridge http://pivotallabs.com/users/nick/blog/articles/455- better-javascript-testing-through-screwunit http://github.com/ndp/wizardize http://www.slideshare.net/jeresig/understanding- javascript-testing http://code.google.com/p/javascript-test-maven- plugin/