ºÝºÝߣ

ºÝºÝߣShare a Scribd company logo
Testing JavaScript
          LIKE A BOSS
                       Jo Cranford
                       @jocranford




Thursday, 19 July 12
Y U NO JAVASCRIPT
                            TESTS?



Thursday, 19 July 12
BDD With Jasmine Is
                         Awesome Sauce

         describe("Score Calculation Behaviour", function() {

             it("should score 0 when no pins are knocked down", function() {

                       var game = new BowlingGame(10);
                       game.roll(0);

                       expect(game.score()).toBe(0);

             });

   });




Thursday, 19 July 12
BDD With Jasmine Is
                         Awesome Sauce

   describe("Score Calculation Behaviour", function() {

             it("should score 0 when no pins are knocked down", function() {

                       var game = new BowlingGame(10);
                       game.roll(0);

                       expect(game.score()).toBe(0);

             });

   });




Thursday, 19 July 12
BDD With Jasmine Is
                         Awesome Sauce

   describe("Score Calculation Behaviour", function() {

             it("should score 0 when no pins are knocked down", function() {

                       var game = new BowlingGame(10);
                       game.roll(0);

                       expect(game.score()).toBe(0);

             });

   });




Thursday, 19 July 12
BDD With Jasmine Is
                         Awesome Sauce

   describe("Score Calculation Behaviour", function() {

             it("should score 0 when no pins are knocked down", function() {

                       var game = new BowlingGame(10);
                       game.roll(0);

                       expect(game.score()).toBe(0);

             });

   });




Thursday, 19 July 12
Basic Shizzle




Thursday, 19 July 12
Jasmine In Your Project


    ?   Ruby Gem

    ?   Maven

    ?   Node.js

    ?   Standalone



Thursday, 19 July 12
Ruby Gem




                              > jasmine init
                              > rake jasmine




                       https://github.com/pivotal/jasmine-gem
Thursday, 19 July 12
Maven

    ?   Searls Jasmine Maven plugin
    ?   Add it to the pom to run tests within the test lifecycle
        phase


                           > mvn jasmine:bdd




            http://searls.github.com/jasmine-maven-plugin/
Thursday, 19 July 12
Node.js

                             > npm install jasmine-node -g




                             > jasmine-node specs/




                       https://github.com/mhevery/jasmine-node
Thursday, 19 July 12
Standalone
    ?   Download the ?les and copy them all across to your
        project.
    ?   Edit the SpecRunner.html to include your JavaScript
        source and tests.
    ?   Open in your favourite browser.




                 https://github.com/pivotal/jasmine/downloads
Thursday, 19 July 12
Now Let¡¯s Write A Test

   ?   describe("Score Calculation Behaviour", function() {

             it("should score 0 when no pins are knocked down", function() {

                       var game = new BowlingGame(10);
                       game.roll(0);

                       expect(game.score()).toBe(0);

             });

   });




Thursday, 19 July 12
?   expect(game.score()).not.toBe(1);



                       expect(true).toBeTruthy();
                       expect(false).toBeFalsy();



                       expect(undefined).toBeUndefined();
                       expect({}).toBeDefined();
                       expect(null).toBeNull();



       expect(1).toBeLessThan(2);
       expect(2).toBeGreaterThan(1);

       expect(new Date(2012, 1, 1).toBeLessThan(new Date(2012, 2, 1));

       expect("aaa").toBeLessThan("bbb");


Thursday, 19 July 12
.toContain()

         describe("How to test for items in an Array", function() {

             it("should tell me if the array contains an item", function() {

                       var theArray = [1, 2, 3];

                       expect(theArray).toContain(1);
                       expect(theArray).not.toContain(4);

             });
   });




Thursday, 19 July 12
.toThrow()

         it("should accept a single digit at a time", function() {

             expect(function() {
                 calculator.enterDigit("2");
             }).not.toThrow();

   });

   it("should not accept letters", function() {

             expect(function() {
                 calculator.enterDigit("a");
             }).toThrow("Only accepts numbers");

   });


Thursday, 19 July 12
.toMatch()

                       it("should compare to a regex", function () {

                        expect("@jocranford").toMatch("@([A-Za-z0-9_]+)");

                });




Thursday, 19 July 12
Before And After

         beforeEach(function() {
               fakeFrame = {
                   addRoll: jasmine.createSpy("Add roll"),
                   isComplete: jasmine.createSpy("Is complete"),
                   setSpareBonus: jasmine.createSpy("spare bonus"),
                   setStrikeBonus: jasmine.createSpy("strike bonus"),
                   score: jasmine.createSpy("score")
               };

   });




Thursday, 19 July 12
Is JavaScript Ever Really
                   That Simple?



Thursday, 19 July 12
What About ...

    ?   Asynchronous goodness

    ?   Interacting with teh DOMz

    ?   Evil Legacy Code

    ?   Continuous Integration

    ?   Clean readable tests that re?ect your domain


Thursday, 19 July 12
Approaches To Testing
                        Asynchronous Code




Thursday, 19 July 12
Let¡¯s Load Some JSON

                       [
                           {
                                "firstName": "Jo",
                                "lastName": "Cranford",
                                "company": "Atlassian"
                           },
                           {
                                "firstName": "Rachel",
                                "lastName": "Laycock",
                                "company": "ThoughtWorks"
                           }
                 ]




Thursday, 19 July 12
The JavaScript Code

                       var Presentation = function() {
                         this.presenters = [];
                 };

                 Presentation.prototype.loadPresenters = function() {
                     var presenters = this.presenters;

                        $.getJSON("people.json", function(data) {
                            $.each(data, function(idx, person) {
                                presenters.push(person);
                            });
                        });
                 };




Thursday, 19 July 12
Easy, Right?

           describe("How not to test an asynchronous function", function
           () {

               it("should load the presenters", function () {

                       var presentation = new Presentation();
                       presentation.loadPresenters();

                       expect(presentation.presenters.length).toBe(2);

               });
    });




Thursday, 19 July 12
Well ... Not So Much.




Thursday, 19 July 12
But This Might Work ...

           describe("Still not ideal though", function () {

              it("should load the presenters", function () {

                       spyOn($, "getJSON").andCallFake(function (url, callback) {
                           callback([{},{}]);
                       })

                       var presentation = new Presentation();
                       presentation.loadPresenters();

                       expect(presentation.presenters.length).toBe(2);

              });
     });



Thursday, 19 July 12
A Little Detour ...




Thursday, 19 July 12
Spy On An Existing Method

           it("can spy on an existing method", function() {

               var fakeElement = $("<div style='display:none'></div>");
               spyOn(fakeElement, 'show');

               var toggleable = new Toggleable(fakeElement);

               toggleable.toggle();

               expect(fakeElement.show).toHaveBeenCalled();

     });




Thursday, 19 July 12
Spy On An Existing Method

           it("can create a method for you", function() {

               var fakeElement = {};
               fakeElement.css = function() {};
               fakeElement.show = jasmine.createSpy("Show spy");

               var toggleable = new Toggleable(fakeElement);

               toggleable.toggle();

               expect(fakeElement.show).toHaveBeenCalled();

     });




Thursday, 19 July 12
Wait, There¡¯s More ...


    ?   expect(spy).not.toHaveBeenCalled()

    ?   createSpy().andReturn(something)

    ?   createSpy().andCallFake(function() {})

    ?   createSpy().andCallThrough()



Thursday, 19 July 12
Spy On The Details

    ?   expect(spy).toHaveBeenCalled()

    ?   expect(spy.callCount).toBe(x)

    ?   expect(spy).toHaveBeenCalledWith()

         ?   Tip: use jasmine.any(Function/Object) for parameters
             you don¡¯t care about


Thursday, 19 July 12
... And We¡¯re Back.


                       Sooooo ... spies are great and all,
                       but what if your callback function
                            takes a while to run?




Thursday, 19 July 12
Don¡¯t Do This At Home.

           Presentation.prototype.loadPresentersMoreSlowly = function() {

               var preso = this;

               $.getJSON("people.json", function(data) {
                   setTimeout(function() {
                       $.each(data, function(idx, person) {
                           preso.presenters.push(person);
                       });
                   }, 2000);
               });

     };



Thursday, 19 July 12
Don¡¯t Do This, Either.
           it("should have loaded after three seconds, right?", function()
           {

               spyOn($, "getJSON").andCallFake(function(url, callback)   {
                   callback([{}, {}]);
               })

               var presentation = new Presentation();
               presentation.loadPresentersMoreSlowly();

               setTimeout(function() {
                   expect(presentation.presenters.length).toBe(2);
               }, 3000);

     });




Thursday, 19 July 12
But What If I Just ...

           Presentation.prototype.loadPresentersMoreSlowly = function() {

               var preso = this;

               $.getJSON("people.json", function(data) {
                   setTimeout(function() {
                       $.each(data, function(idx, person) {
                           preso.presenters.push(person);
                       });
                       preso.presentersHaveLoaded = true;
                   }, 2000);
               });

     };



Thursday, 19 July 12
Now Wait, Wait ... RUN!
                 it("should load the presenters", function() {

                       spyOn($, "getJSON").andCallFake(function(url, callback) {
                           callback([{}, {}]);
                       })

                       var presentation = new Presentation();
                       presentation.loadPresentersMoreSlowly();

                       waitsFor(function() {
                           return presentation.presentersHaveLoaded;
                       }, "presenters have loaded");

                       runs(function() {
                           expect(presentation.presenters.length).toBe(2);
                       });

           });

Thursday, 19 July 12
Testing Interaction With The
                    DOM

    ?   Do you REALLY need to?

    ?   Tests will have a high maintenance cost

    ?   Instead separate logic from view and test logic

    ?   Use templates for the view



Thursday, 19 July 12
Testing Interaction With The
                  DOM
            it("should display the score", function() {

                setFixtures("<div id='score'></div>");

                var bowlingGameView = new BowlingGameView();
                bowlingGameView.showScore(100);

                expect($("#score").text()).toBe("Your current score is 100");

      });




                       https://github.com/velesin/jasmine-jquery
Thursday, 19 July 12
Legacy (untested)
                        JavaScript Code
    ?   Long methods

    ?   Violation of Single Responsibility Principle

    ?   Side effects

    ?   Lack of dependency injection

    ?   Lots of new X()

    ?   Unclear intentions

Thursday, 19 July 12
Testing Interaction

          it("should call the method on the dependency", function() {

                       var dependency = {};
                       dependency.method = jasmine.createSpy();

                       var myObject = new Something(dependency);
                       myObject.doSomething();

                       expect(dependency.method).toHaveBeenCalled();
          });




Thursday, 19 July 12
If Dependencies Aren¡¯t
                             Injected ...

          var LegacySomething = function() {

                       this.doSomething = function() {
                           var dependency = new Dependency();
                           dependency.method();
                       };

          };




Thursday, 19 July 12
Create Stubs

          it("is a pain but not impossible", function() {

                       Dependency = function() {};
                       Dependency.prototype.method = jasmine.createSpy()

                       var myObject = new LegacySomething();
                       myObject.doSomething();

                       expect(Dependency.prototype.method).toHaveBeenCalled();
          });




Thursday, 19 July 12
Continuous Integration


    ?   Ruby Gem

    ?   Maven

    ?   Node.js

    ?   Rhino (Java)



Thursday, 19 July 12
Ruby Gem
                        require 'jasmine'
                        load 'jasmine/tasks/jasmine.rake'




                              > rake jasmine:ci




                       https://github.com/pivotal/jasmine-gem
Thursday, 19 July 12
Maven


                               > mvn clean test




               http://searls.github.com/jasmine-maven-plugin/
Thursday, 19 July 12
Node.js


                             > jasmine-node specs/




                       https://github.com/mhevery/jasmine-node
Thursday, 19 July 12
Rhino

    ?   Download:

         ?   Rhino (js.jar) from Mozilla

         ?   env.rhino.js from www.envjs.com

         ?   Jasmine console reporter from Larry Myers Jasmine
             Reporters project (github)



                 http://www.build-doctor.com/2010/12/08/javascript-bdd-jasmine/
Thursday, 19 July 12
Rhino
                 load('env.rhino.1.2.js');

           Envjs.scriptTypes['text/javascript'] = true;

           var specFile;

           for (i = 0; i < arguments.length; i++) {
               specFile = arguments[i];

                       console.log("Loading: " + specFile);

                       window.location = specFile
           }



          > java -jar js.jar -opt -1 env.bootstrap.js ../SpecRunner.html



Thursday, 19 July 12
Extending Jasmine With
                    Custom Matchers
               it("should match the latitude and longitude", function() {

                   var pointOnMap = { latitude: "51.23", longitude: "-10.14" };

                   expect(pointOnMap.latitude).toBe("51.23");
                   expect(pointOnMap.longitude).toBe("-10.14");

         });

         it("should match the latitude and longitude", function() {

                   var pointOnMap = { latitude: "51.23", longitude: "-10.14" };

                   expect(pointOnMap).toHaveLatitude("51.23");
                   expect(pointOnMap).toHaveLongitude("-10.14");

         });


Thursday, 19 July 12
Extending Jasmine With
                    Custom Matchers

         it("should match the latitude and longitude", function() {

             var pointOnMap = { latitude: "51.23", longitude: "-10.14" };

             expect(pointOnMap).toHaveLatLongCoordinates("51.23", "-10.14");

   });




Thursday, 19 July 12
Extending Jasmine With
                    Custom Matchers

   beforeEach(function() {
       this.addMatchers({
           toHaveLatitude: function(lat) {
               return this.actual.latitude === lat;
           },
           toHaveLongitude: function(lat) {
               return this.actual.latitude === lat;
           },
           toHaveLatLongCoordinates: function(lat, lng) {
               return (this.actual.latitude === lat &&
                  this.actual.longitude === lng);
           }
       });
   });


Thursday, 19 July 12
Custom Failure Messages


          toHaveLatitude: function(lat) {
              this.message = function() {
                  return "Expected Latitude " + this.actual.latitude
                    + " to be " + lat;
              };
              return this.actual.latitude === lat;
          }




Thursday, 19 July 12
Do We Really Need To Test
                Everything?
         DO:                         DON¡¯T:

     ?   Test Behaviour and          ?   Over-test DOM interaction
         Functionality
                                     ?   Test Getters and Setters
     ?   Test the places where the
         bad bugs bite             ? Test functionality in third
                                     party libraries

                                     ?   Write tests that are
                                         expensive to maintain
Thursday, 19 July 12
Tips & Gotchas

    ?   Tests aren¡¯t completely independent!

    ?   If tests are hard to write, it¡¯s often an indication of a smell
        in the code

    ?   Automate creation of SpecRunner.html

    ?   Run tests in different browsers




Thursday, 19 July 12
With thanks to our sponsors




Thursday, 19 July 12
Please complete your feedback
           forms, and return them to the
          registration desk for a chance
                                to win a
                           Nokia Lumia




Thursday, 19 July 12
Questions




Thursday, 19 July 12

More Related Content

Testing javascriptwithjasmine ddd-sydney

  • 1. Testing JavaScript LIKE A BOSS Jo Cranford @jocranford Thursday, 19 July 12
  • 2. Y U NO JAVASCRIPT TESTS? Thursday, 19 July 12
  • 3. BDD With Jasmine Is Awesome Sauce describe("Score Calculation Behaviour", function() { it("should score 0 when no pins are knocked down", function() { var game = new BowlingGame(10); game.roll(0); expect(game.score()).toBe(0); }); }); Thursday, 19 July 12
  • 4. BDD With Jasmine Is Awesome Sauce describe("Score Calculation Behaviour", function() { it("should score 0 when no pins are knocked down", function() { var game = new BowlingGame(10); game.roll(0); expect(game.score()).toBe(0); }); }); Thursday, 19 July 12
  • 5. BDD With Jasmine Is Awesome Sauce describe("Score Calculation Behaviour", function() { it("should score 0 when no pins are knocked down", function() { var game = new BowlingGame(10); game.roll(0); expect(game.score()).toBe(0); }); }); Thursday, 19 July 12
  • 6. BDD With Jasmine Is Awesome Sauce describe("Score Calculation Behaviour", function() { it("should score 0 when no pins are knocked down", function() { var game = new BowlingGame(10); game.roll(0); expect(game.score()).toBe(0); }); }); Thursday, 19 July 12
  • 8. Jasmine In Your Project ? Ruby Gem ? Maven ? Node.js ? Standalone Thursday, 19 July 12
  • 9. Ruby Gem > jasmine init > rake jasmine https://github.com/pivotal/jasmine-gem Thursday, 19 July 12
  • 10. Maven ? Searls Jasmine Maven plugin ? Add it to the pom to run tests within the test lifecycle phase > mvn jasmine:bdd http://searls.github.com/jasmine-maven-plugin/ Thursday, 19 July 12
  • 11. Node.js > npm install jasmine-node -g > jasmine-node specs/ https://github.com/mhevery/jasmine-node Thursday, 19 July 12
  • 12. Standalone ? Download the ?les and copy them all across to your project. ? Edit the SpecRunner.html to include your JavaScript source and tests. ? Open in your favourite browser. https://github.com/pivotal/jasmine/downloads Thursday, 19 July 12
  • 13. Now Let¡¯s Write A Test ? describe("Score Calculation Behaviour", function() { it("should score 0 when no pins are knocked down", function() { var game = new BowlingGame(10); game.roll(0); expect(game.score()).toBe(0); }); }); Thursday, 19 July 12
  • 14. ? expect(game.score()).not.toBe(1); expect(true).toBeTruthy(); expect(false).toBeFalsy(); expect(undefined).toBeUndefined(); expect({}).toBeDefined(); expect(null).toBeNull(); expect(1).toBeLessThan(2); expect(2).toBeGreaterThan(1); expect(new Date(2012, 1, 1).toBeLessThan(new Date(2012, 2, 1)); expect("aaa").toBeLessThan("bbb"); Thursday, 19 July 12
  • 15. .toContain() describe("How to test for items in an Array", function() { it("should tell me if the array contains an item", function() { var theArray = [1, 2, 3]; expect(theArray).toContain(1); expect(theArray).not.toContain(4); }); }); Thursday, 19 July 12
  • 16. .toThrow() it("should accept a single digit at a time", function() { expect(function() { calculator.enterDigit("2"); }).not.toThrow(); }); it("should not accept letters", function() { expect(function() { calculator.enterDigit("a"); }).toThrow("Only accepts numbers"); }); Thursday, 19 July 12
  • 17. .toMatch() it("should compare to a regex", function () { expect("@jocranford").toMatch("@([A-Za-z0-9_]+)"); }); Thursday, 19 July 12
  • 18. Before And After beforeEach(function() { fakeFrame = { addRoll: jasmine.createSpy("Add roll"), isComplete: jasmine.createSpy("Is complete"), setSpareBonus: jasmine.createSpy("spare bonus"), setStrikeBonus: jasmine.createSpy("strike bonus"), score: jasmine.createSpy("score") }; }); Thursday, 19 July 12
  • 19. Is JavaScript Ever Really That Simple? Thursday, 19 July 12
  • 20. What About ... ? Asynchronous goodness ? Interacting with teh DOMz ? Evil Legacy Code ? Continuous Integration ? Clean readable tests that re?ect your domain Thursday, 19 July 12
  • 21. Approaches To Testing Asynchronous Code Thursday, 19 July 12
  • 22. Let¡¯s Load Some JSON [ { "firstName": "Jo", "lastName": "Cranford", "company": "Atlassian" }, { "firstName": "Rachel", "lastName": "Laycock", "company": "ThoughtWorks" } ] Thursday, 19 July 12
  • 23. The JavaScript Code var Presentation = function() { this.presenters = []; }; Presentation.prototype.loadPresenters = function() { var presenters = this.presenters; $.getJSON("people.json", function(data) { $.each(data, function(idx, person) { presenters.push(person); }); }); }; Thursday, 19 July 12
  • 24. Easy, Right? describe("How not to test an asynchronous function", function () { it("should load the presenters", function () { var presentation = new Presentation(); presentation.loadPresenters(); expect(presentation.presenters.length).toBe(2); }); }); Thursday, 19 July 12
  • 25. Well ... Not So Much. Thursday, 19 July 12
  • 26. But This Might Work ... describe("Still not ideal though", function () { it("should load the presenters", function () { spyOn($, "getJSON").andCallFake(function (url, callback) { callback([{},{}]); }) var presentation = new Presentation(); presentation.loadPresenters(); expect(presentation.presenters.length).toBe(2); }); }); Thursday, 19 July 12
  • 27. A Little Detour ... Thursday, 19 July 12
  • 28. Spy On An Existing Method it("can spy on an existing method", function() { var fakeElement = $("<div style='display:none'></div>"); spyOn(fakeElement, 'show'); var toggleable = new Toggleable(fakeElement); toggleable.toggle(); expect(fakeElement.show).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 29. Spy On An Existing Method it("can create a method for you", function() { var fakeElement = {}; fakeElement.css = function() {}; fakeElement.show = jasmine.createSpy("Show spy"); var toggleable = new Toggleable(fakeElement); toggleable.toggle(); expect(fakeElement.show).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 30. Wait, There¡¯s More ... ? expect(spy).not.toHaveBeenCalled() ? createSpy().andReturn(something) ? createSpy().andCallFake(function() {}) ? createSpy().andCallThrough() Thursday, 19 July 12
  • 31. Spy On The Details ? expect(spy).toHaveBeenCalled() ? expect(spy.callCount).toBe(x) ? expect(spy).toHaveBeenCalledWith() ? Tip: use jasmine.any(Function/Object) for parameters you don¡¯t care about Thursday, 19 July 12
  • 32. ... And We¡¯re Back. Sooooo ... spies are great and all, but what if your callback function takes a while to run? Thursday, 19 July 12
  • 33. Don¡¯t Do This At Home. Presentation.prototype.loadPresentersMoreSlowly = function() { var preso = this; $.getJSON("people.json", function(data) { setTimeout(function() { $.each(data, function(idx, person) { preso.presenters.push(person); }); }, 2000); }); }; Thursday, 19 July 12
  • 34. Don¡¯t Do This, Either. it("should have loaded after three seconds, right?", function() { spyOn($, "getJSON").andCallFake(function(url, callback) { callback([{}, {}]); }) var presentation = new Presentation(); presentation.loadPresentersMoreSlowly(); setTimeout(function() { expect(presentation.presenters.length).toBe(2); }, 3000); }); Thursday, 19 July 12
  • 35. But What If I Just ... Presentation.prototype.loadPresentersMoreSlowly = function() { var preso = this; $.getJSON("people.json", function(data) { setTimeout(function() { $.each(data, function(idx, person) { preso.presenters.push(person); }); preso.presentersHaveLoaded = true; }, 2000); }); }; Thursday, 19 July 12
  • 36. Now Wait, Wait ... RUN! it("should load the presenters", function() { spyOn($, "getJSON").andCallFake(function(url, callback) { callback([{}, {}]); }) var presentation = new Presentation(); presentation.loadPresentersMoreSlowly(); waitsFor(function() { return presentation.presentersHaveLoaded; }, "presenters have loaded"); runs(function() { expect(presentation.presenters.length).toBe(2); }); }); Thursday, 19 July 12
  • 37. Testing Interaction With The DOM ? Do you REALLY need to? ? Tests will have a high maintenance cost ? Instead separate logic from view and test logic ? Use templates for the view Thursday, 19 July 12
  • 38. Testing Interaction With The DOM it("should display the score", function() { setFixtures("<div id='score'></div>"); var bowlingGameView = new BowlingGameView(); bowlingGameView.showScore(100); expect($("#score").text()).toBe("Your current score is 100"); }); https://github.com/velesin/jasmine-jquery Thursday, 19 July 12
  • 39. Legacy (untested) JavaScript Code ? Long methods ? Violation of Single Responsibility Principle ? Side effects ? Lack of dependency injection ? Lots of new X() ? Unclear intentions Thursday, 19 July 12
  • 40. Testing Interaction it("should call the method on the dependency", function() { var dependency = {}; dependency.method = jasmine.createSpy(); var myObject = new Something(dependency); myObject.doSomething(); expect(dependency.method).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 41. If Dependencies Aren¡¯t Injected ... var LegacySomething = function() { this.doSomething = function() { var dependency = new Dependency(); dependency.method(); }; }; Thursday, 19 July 12
  • 42. Create Stubs it("is a pain but not impossible", function() { Dependency = function() {}; Dependency.prototype.method = jasmine.createSpy() var myObject = new LegacySomething(); myObject.doSomething(); expect(Dependency.prototype.method).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 43. Continuous Integration ? Ruby Gem ? Maven ? Node.js ? Rhino (Java) Thursday, 19 July 12
  • 44. Ruby Gem require 'jasmine' load 'jasmine/tasks/jasmine.rake' > rake jasmine:ci https://github.com/pivotal/jasmine-gem Thursday, 19 July 12
  • 45. Maven > mvn clean test http://searls.github.com/jasmine-maven-plugin/ Thursday, 19 July 12
  • 46. Node.js > jasmine-node specs/ https://github.com/mhevery/jasmine-node Thursday, 19 July 12
  • 47. Rhino ? Download: ? Rhino (js.jar) from Mozilla ? env.rhino.js from www.envjs.com ? Jasmine console reporter from Larry Myers Jasmine Reporters project (github) http://www.build-doctor.com/2010/12/08/javascript-bdd-jasmine/ Thursday, 19 July 12
  • 48. Rhino load('env.rhino.1.2.js'); Envjs.scriptTypes['text/javascript'] = true; var specFile; for (i = 0; i < arguments.length; i++) { specFile = arguments[i]; console.log("Loading: " + specFile); window.location = specFile } > java -jar js.jar -opt -1 env.bootstrap.js ../SpecRunner.html Thursday, 19 July 12
  • 49. Extending Jasmine With Custom Matchers it("should match the latitude and longitude", function() { var pointOnMap = { latitude: "51.23", longitude: "-10.14" }; expect(pointOnMap.latitude).toBe("51.23"); expect(pointOnMap.longitude).toBe("-10.14"); }); it("should match the latitude and longitude", function() { var pointOnMap = { latitude: "51.23", longitude: "-10.14" }; expect(pointOnMap).toHaveLatitude("51.23"); expect(pointOnMap).toHaveLongitude("-10.14"); }); Thursday, 19 July 12
  • 50. Extending Jasmine With Custom Matchers it("should match the latitude and longitude", function() { var pointOnMap = { latitude: "51.23", longitude: "-10.14" }; expect(pointOnMap).toHaveLatLongCoordinates("51.23", "-10.14"); }); Thursday, 19 July 12
  • 51. Extending Jasmine With Custom Matchers beforeEach(function() { this.addMatchers({ toHaveLatitude: function(lat) { return this.actual.latitude === lat; }, toHaveLongitude: function(lat) { return this.actual.latitude === lat; }, toHaveLatLongCoordinates: function(lat, lng) { return (this.actual.latitude === lat && this.actual.longitude === lng); } }); }); Thursday, 19 July 12
  • 52. Custom Failure Messages toHaveLatitude: function(lat) { this.message = function() { return "Expected Latitude " + this.actual.latitude + " to be " + lat; }; return this.actual.latitude === lat; } Thursday, 19 July 12
  • 53. Do We Really Need To Test Everything? DO: DON¡¯T: ? Test Behaviour and ? Over-test DOM interaction Functionality ? Test Getters and Setters ? Test the places where the bad bugs bite ? Test functionality in third party libraries ? Write tests that are expensive to maintain Thursday, 19 July 12
  • 54. Tips & Gotchas ? Tests aren¡¯t completely independent! ? If tests are hard to write, it¡¯s often an indication of a smell in the code ? Automate creation of SpecRunner.html ? Run tests in different browsers Thursday, 19 July 12
  • 55. With thanks to our sponsors Thursday, 19 July 12
  • 56. Please complete your feedback forms, and return them to the registration desk for a chance to win a Nokia Lumia Thursday, 19 July 12