Testing javascriptwithjasmine sydjs
-
Upload
jo-cranford -
Category
Technology
-
view
878 -
download
0
description
Transcript of Testing javascriptwithjasmine sydjs
![Page 1: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/1.jpg)
Testing JavaScriptLIKE A BOSS
Jo Cranford@jocranford
Thursday, 19 July 12
![Page 2: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/2.jpg)
Y U NO JAVASCRIPT TESTS?
Thursday, 19 July 12
![Page 3: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/3.jpg)
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
![Page 4: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/4.jpg)
Is JavaScript Ever Really That Simple?
Thursday, 19 July 12
![Page 5: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/5.jpg)
What About ...
• Asynchronous goodness
• Interacting with teh DOMz
• Evil Legacy Code
• Continuous Integration
• Clean readable tests that reflect your domain
Thursday, 19 July 12
![Page 6: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/6.jpg)
Approaches To Testing Asynchronous Code
Thursday, 19 July 12
![Page 7: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/7.jpg)
Let’s Load Some JSON
[ { "firstName": "Jo", "lastName": "Cranford", "company": "Atlassian" }, { "firstName": "Rachel", "lastName": "Laycock", "company": "ThoughtWorks" }]
Thursday, 19 July 12
![Page 8: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/8.jpg)
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
![Page 9: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/9.jpg)
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
![Page 10: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/10.jpg)
Well ... Not So Much.
Thursday, 19 July 12
![Page 11: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/11.jpg)
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
![Page 12: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/12.jpg)
A Little Detour ...
Thursday, 19 July 12
![Page 13: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/13.jpg)
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
![Page 14: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/14.jpg)
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
![Page 15: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/15.jpg)
Wait, There’s More ...
• expect(spy).not.toHaveBeenCalled()
• createSpy().andReturn(something)
• createSpy().andCallFake(function() {})
• createSpy().andCallThrough()
Thursday, 19 July 12
![Page 16: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/16.jpg)
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
![Page 17: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/17.jpg)
... 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
![Page 18: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/18.jpg)
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
![Page 19: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/19.jpg)
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
![Page 20: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/20.jpg)
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
![Page 21: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/21.jpg)
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
![Page 22: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/22.jpg)
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
![Page 23: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/23.jpg)
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-jqueryThursday, 19 July 12
![Page 24: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/24.jpg)
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
![Page 25: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/25.jpg)
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
![Page 26: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/26.jpg)
If Dependencies Aren’t Injected ...
var LegacySomething = function() {
this.doSomething = function() { var dependency = new Dependency(); dependency.method(); };
};
Thursday, 19 July 12
![Page 27: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/27.jpg)
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
![Page 28: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/28.jpg)
Continuous Integration
• Ruby Gem
• Maven
• Node.js
• Rhino (Java)
Thursday, 19 July 12
![Page 29: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/29.jpg)
Ruby Gem
> rake jasmine:ci
require 'jasmine'load 'jasmine/tasks/jasmine.rake'
https://github.com/pivotal/jasmine-gemThursday, 19 July 12
![Page 30: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/30.jpg)
Maven
> mvn clean test
http://searls.github.com/jasmine-maven-plugin/Thursday, 19 July 12
![Page 31: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/31.jpg)
Node.js
> jasmine-node specs/
https://github.com/mhevery/jasmine-nodeThursday, 19 July 12
![Page 32: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/32.jpg)
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
![Page 33: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/33.jpg)
Rhinoload('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
![Page 34: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/34.jpg)
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
![Page 35: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/35.jpg)
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
![Page 36: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/36.jpg)
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
![Page 37: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/37.jpg)
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
![Page 38: Testing javascriptwithjasmine sydjs](https://reader036.fdocuments.in/reader036/viewer/2022062512/554a1224b4c905825d8b4b69/html5/thumbnails/38.jpg)
Thursday, 19 July 12