SlideShare une entreprise Scribd logo
1  sur  48
Télécharger pour lire hors ligne
Front End Workshops
VI.JavaScript testing. Client vs.
Server testing. Test Driven
Development
Raúl Delgado Astudillo
rdelgado@visual-engin.com
Mario García Martín
mgarcia@visual-engin.com
JavaScript testing
“Testing is an infinite process of comparing the invisible to the
ambiguous in order to avoid the unthinkable happening to the
anonymous.”
— James Bach
What is a test?
Type some code
Open and load the browser
Prove functionality
A test is (simply) the validation of an expectation.
Manual testing...
...is
NOT
enough!
Can we do better?
Manual testing is...
Time consuming
Error prone
Irreproducible
(Nearly) Impossible if we want to test a
wide set of browsers and platforms
YES!!
Automated
testing
Tests should be
Fast to run
Easy to understand
Isolated
Not reliant on an Internet connection
Benefits and pitfalls of testing
Regression testing
Refactoring
Cross-browser testing
Good documentation
Helps us write cleaner
interfaces (testable code)
Writing good tests can be
challenging
More information in...
● Test-Driven JavaScript Development, by Christian Johansen
● https://en.wikipedia.org/wiki/Software_testing
Client testing
“A passing test doesn't mean no problem. It means no problem
observed. This time. With these inputs. So far. On my machine.”
— Michael Bolton
Frameworks
Jasmine — Scaffolding
describe("A suite with setup and tear-down", function() {
var foo;
beforeAll(function() {});
afterAll(function() {});
beforeEach(function() {
foo = 1;
});
afterEach(function() {
foo = 0;
});
it("can contain specs with one or more expectations", function() {
expect(foo).toBe(1);
expect(true).toBe(true);
});
});
Matchers
expect(3).toBe(3); // Compares with ===
expect({a: 3}).toEqual({a: 3}); // For comparison of objects
expect('barely').toMatch(/bar/); // For regular expressions
expect(null).toBeDefined(); // Compares against undefined
expect(undefined).toBeUndefined(); // Compares against undefined
expect(null).toBeNull(); // Compares against null
expect('hello').toBeTruthy(); // For boolean casting testing
expect('').toBeFalsy(); // For boolean casting testing
expect(['bar', 'foo']).toContain('bar'); // For finding an item in an Array
expect(2).toBeLessThan(3); // For mathematical comparisons
expect(3).toBeGreaterThan(2); // For mathematical comparisons
expect(3.14).toBeCloseTo(3.17, 1); // For precision math comparison
// For testing if a function throws an exception
expect(function() { throw new Error('Error!'); }).toThrow();
// Modifier 'not'
expect(false).not.toBe(true);
Spies
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = { setBar: function(value) { bar = value; } };
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'another param');
});
it("that defines a spy out of the box", function() {
expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called
// tracks all the arguments of its calls
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
expect(bar).toBeNull(); // stops all execution on a function
});
});
Spies — and.callthrough
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) { bar = value; }
};
spyOn(foo, 'setBar').and.callThrough();
foo.setBar(123);
});
it("that defines a spy configured to call through", function() {
expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called
expect(bar).toEqual(123); // the spied function has been called
});
});
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
getBar: function() { return bar; }
};
spyOn(foo, 'getBar').and.returnValue(745);
});
it("that defines a spy configured to fake a return value", function() {
expect(foo.getBar()).toBe(745); // when called returns the requested value
expect(bar).toBeNull(); // should not affect the variable
});
});
Spies — and.returnValue
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) { bar = value; }
};
spyOn(foo, 'setBar').and.callFake(function() {
console.log('hello');
});
foo.setBar(); // logs hello in the console.
});
it("that defines a spy configured with an alternate implementation", function() {
expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called
expect(bar).toBeNull(); // should not affect the variable
});
});
Spies — and.callFake
Spies — createSpy
describe("A suite", function() {
var spy;
beforeAll(function() {
$(window).on('resize', function() { $(window).trigger('myEvent'); });
});
afterAll(function() {
$(window).off('resize');
});
beforeEach(function() {
spy = jasmine.createSpy();
});
it("that defines a spy created manually", function() {
$(window).on('myEvent', spy);
$(window).trigger('resize');
expect(spy).toHaveBeenCalled(); // tracks that the spy was called
});
});
Spies — Other tracking properties (I)
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = { setBar: function(value) { bar = value; } };
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'baz');
});
it("has a rich set of tracking properties", function() {
expect(foo.setBar.calls.count()).toEqual(2); // tracks the number of calls
// tracks the args of each call
expect(foo.setBar.calls.argsFor(0)).toEqual([123]);
expect(foo.setBar.calls.argsFor(1)).toEqual([456, 'baz']);
// has shortcuts to the first and most recent call
expect(foo.setBar.calls.first().args).toEqual([123]);
expect(foo.setBar.calls.mostRecent().args).toEqual([456, 'baz']);
});
});
Spies — Other tracking properties (II)
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = { setBar: function(value) { bar = value; } };
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'baz');
});
it("has a rich set of tracking properties", function() {
// tracks the context and return values
expect(foo.setBar.calls.first().object).toEqual(foo);
expect(foo.setBar.calls.first().returnValue).toBeUndefined();
// can be reset
foo.setBar.calls.reset();
expect(foo.setBar.calls.count()).toBe(0);
});
});
Asynchronous support
describe("Asynchronous specs", function() {
var value;
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 100);
});
it("should support async execution of preparation and expectations", function(done) {
expect(value).toBe(0);
done();
});
});
Clock
describe("Manually ticking the Jasmine Clock", function() {
var timerCallback;
beforeEach(function() {
timerCallback = jasmine.createSpy();
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("causes a timeout to be called synchronously", function() {
setTimeout(timerCallback, 100);
expect(timerCallback).not.toHaveBeenCalled();
jasmine.clock().tick(101);
expect(timerCallback).toHaveBeenCalled();
});
});
Clock — Mocking the date
describe("Mocking the Date object", function() {
beforeEach(function() {
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("mocks the Date object and sets it to a given time", function() {
var baseTime = new Date(2013, 9, 23);
jasmine.clock().mockDate(baseTime);
jasmine.clock().tick(50);
expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
});
});
Sinon — Spies and Stubs
var spy = sinon.spy();
sinon.spy($, 'ajax');
$.ajax.restore();
sinon.stub($, 'ajax');
$.ajax.restore();
sinon.stub($, 'ajax', function(options) {
console.log(options.url);
});
$.ajax.restore();
Sinon — Fake timer
describe("Manually ticking the Clock", function() {
var clock, timerCallback;
beforeEach(function() {
timerCallback = sinon.spy();
clock = sinon.useFakeTimers();
});
afterEach(function() {
clock.restore();
});
it("causes a timeout to be called synchronously", function() {
setTimeout(timerCallback, 100);
expect(timerCallback.callCount).toBe(0);
clock.tick(101);
expect(timerCallback.callCount).toBe(1);
expect(new Date().getTime()).toBe(101);
});
});
Sinon — Fake server
describe("A suite with a sinon fakeServer", function() {
var server;
beforeEach(function() {
server = sinon.fakeServer.create();
server.autoRespond = true;
server.respondWith(function(xhr) {
xhr.respond(200, {'Content-Type':'application/json'}, JSON.stringify({'msg': 'msg'}));
});
server.xhr.useFilters = true;
server.xhr.addFilter(function(method, url) {
return !!url.match(/fixtures|css/); // If returns true the request will not be faked.
});
});
afterEach(function() {
server.restore();
});
});
More information in...
● https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#JavaScri
pt
● http://stackoverflow.com/questions/300855/javascript-unit-test-tools-
for-tdd
● http://jasmine.github.io/
● http://sinonjs.org/
Test Driven Development
“The best TDD can do is assure that the code does what the
programmer thinks it should do. That is pretty good by the way.”
— James Grenning
The cycle of TDD
Write a test
Run tests. Watch the new test fail
Make the test pass
Refactor to remove duplication
Benefits of TDD
Produces code that works
Honors the Single Responsibility Principle
Forces conscious development
Productivity boost
More information in...
● Test-Driven Development By Example, by Kent Beck.
Jasmine Disabling specs
xdescribe("A disabled suite", function() {
it("where the specs will not be executed", function() {
expect(2).toEqual(1);
});
});
describe("A suite", function() {
xit("with a disabled spec declared with 'xit'", function() {
expect(true).toBe(false);
});
it.only("with a spec that will be executed", function() {
expect(1).toBe(1);
});
it("with another spec that will not be executed", function() {
expect(1).toBe(1);
});
});
Asynchronous support
describe("long asynchronous specs", function() {
beforeEach(function(done) {
done();
}, 1000);
afterEach(function(done) {
done();
}, 1000);
it("takes a long time", function(done) {
setTimeout(done, 9000);
}, 10000);
});
Asynchronous support. Jasmine 1.3
describe("Asynchronous specs", function() {
var value, flag;
it("should support async execution of test preparation and expectations", function() {
flag = false;
value = 0;
setTimeout(function() {
flag = true;
}, 500);
waitsFor(function() {
value++;
return flag;
}, "The Value should be incremented", 750);
runs(function() {
expect(value).toBeGreaterThan(0);
});
});
});
jasmine.Clock v.1.3
it('description', function() {
jasmine.Clock.useMock();
setTimeout(function() {
console.log('print something');
}, 200);
jasmine.Clock.tick(190);
});
it('description', function() {
jasmine.Clock.useMock();
jasmine.Clock.tick(190);
});
Karma
npm install karma --save-dev
npm install karma-jasmine karma-chrome-launcher karma-phantomjs-launcher --save-dev
npm install karma-coverage --save-dev
npm install -g karma-cli
Installation
Configuration
karma init karma.conf.js npm install grunt-karma --save-dev
grunt.loadNpmTasks('grunt-karma');
karma: {
unit: {
configFile: 'karma.conf.js'
}
}
Grunt task
Karma configuration
The files array determines which files are included in the browser and which files are watched and
served by Karma.
Each pattern is either a simple string or an object with four properties:
pattern String, no default value. The pattern to use for matching. This property is mandatory.
watched Boolean (true). If autoWatch is true all files that have set watched to true will be watched
for changes.
included Boolean (true). Should the files be included in the browser using <script> tag? Use false if
you want to load them manually, eg. using Require.js.
served Boolean (true). Should the files be served by Karma's webserver?
THANKS FOR YOUR ATTENTION
Leave your questions on the comments section
Workshop 5: JavaScript testing

Contenu connexe

Tendances

Tendances (20)

Say It With Javascript
Say It With JavascriptSay It With Javascript
Say It With Javascript
 
Advanced javascript
Advanced javascriptAdvanced javascript
Advanced javascript
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascript
 
ES2015 workflows
ES2015 workflowsES2015 workflows
ES2015 workflows
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
 
Oojs 1.1
Oojs 1.1Oojs 1.1
Oojs 1.1
 
Practical JavaScript Programming - Session 7/8
Practical JavaScript Programming - Session 7/8Practical JavaScript Programming - Session 7/8
Practical JavaScript Programming - Session 7/8
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」
 
Practical JavaScript Programming - Session 8/8
Practical JavaScript Programming - Session 8/8Practical JavaScript Programming - Session 8/8
Practical JavaScript Programming - Session 8/8
 
Unit testing with mocha
Unit testing with mochaUnit testing with mocha
Unit testing with mocha
 
Inversion Of Control
Inversion Of ControlInversion Of Control
Inversion Of Control
 
Javascript ES6 generators
Javascript ES6 generatorsJavascript ES6 generators
Javascript ES6 generators
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
Powerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best PracticesPowerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best Practices
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
 
Java Script Best Practices
Java Script Best PracticesJava Script Best Practices
Java Script Best Practices
 
To Err Is Human
To Err Is HumanTo Err Is Human
To Err Is Human
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboards
 
05 JavaScript #burningkeyboards
05 JavaScript #burningkeyboards05 JavaScript #burningkeyboards
05 JavaScript #burningkeyboards
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0
 

En vedette

En vedette (8)

Workshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJSWorkshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJS
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte III
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte II
 
Workshop 15: Ionic framework
Workshop 15: Ionic frameworkWorkshop 15: Ionic framework
Workshop 15: Ionic framework
 
Workshop 9: BackboneJS y patrones MVC
Workshop 9: BackboneJS y patrones MVCWorkshop 9: BackboneJS y patrones MVC
Workshop 9: BackboneJS y patrones MVC
 
Workshop 7: Single Page Applications
Workshop 7: Single Page ApplicationsWorkshop 7: Single Page Applications
Workshop 7: Single Page Applications
 
Legal protection in public procurement, Zoran Blazevic, SIGMA regional confer...
Legal protection in public procurement, Zoran Blazevic, SIGMA regional confer...Legal protection in public procurement, Zoran Blazevic, SIGMA regional confer...
Legal protection in public procurement, Zoran Blazevic, SIGMA regional confer...
 
Workshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IWorkshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte I
 

Similaire à Workshop 5: JavaScript testing

The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5a
rajivmordani
 

Similaire à Workshop 5: JavaScript testing (20)

Stop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScriptStop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScript
 
Introduccion a Jasmin
Introduccion a JasminIntroduccion a Jasmin
Introduccion a Jasmin
 
Angular promises and http
Angular promises and httpAngular promises and http
Angular promises and http
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the masters
 
How to test complex SaaS applications - The family july 2014
How to test complex SaaS applications - The family july 2014How to test complex SaaS applications - The family july 2014
How to test complex SaaS applications - The family july 2014
 
The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5a
 
Introduction to Protractor
Introduction to ProtractorIntroduction to Protractor
Introduction to Protractor
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
The Beauty of Java Script
The Beauty of Java ScriptThe Beauty of Java Script
The Beauty of Java Script
 
04 Advanced Javascript
04 Advanced Javascript04 Advanced Javascript
04 Advanced Javascript
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql
 
Call stack, event loop and async programming
Call stack, event loop and async programmingCall stack, event loop and async programming
Call stack, event loop and async programming
 
Jasmine BDD for Javascript
Jasmine BDD for JavascriptJasmine BDD for Javascript
Jasmine BDD for Javascript
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
 
Sane Async Patterns
Sane Async PatternsSane Async Patterns
Sane Async Patterns
 
AngularJS Testing
AngularJS TestingAngularJS Testing
AngularJS Testing
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
 
jQuery: Events, Animation, Ajax
jQuery: Events, Animation, AjaxjQuery: Events, Animation, Ajax
jQuery: Events, Animation, Ajax
 
Node.js - Best practices
Node.js  - Best practicesNode.js  - Best practices
Node.js - Best practices
 

Plus de Visual Engineering

Plus de Visual Engineering (20)

Workshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSWorkshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJS
 
Workshop iOS 4: Closures, generics & operators
Workshop iOS 4: Closures, generics & operatorsWorkshop iOS 4: Closures, generics & operators
Workshop iOS 4: Closures, generics & operators
 
Workshop iOS 3: Testing, protocolos y extensiones
Workshop iOS 3: Testing, protocolos y extensionesWorkshop iOS 3: Testing, protocolos y extensiones
Workshop iOS 3: Testing, protocolos y extensiones
 
Workshop iOS 2: Swift - Structures
Workshop iOS 2: Swift - StructuresWorkshop iOS 2: Swift - Structures
Workshop iOS 2: Swift - Structures
 
Workhop iOS 1: Fundamentos de Swift
Workhop iOS 1: Fundamentos de SwiftWorkhop iOS 1: Fundamentos de Swift
Workhop iOS 1: Fundamentos de Swift
 
Workshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideWorkshop 26: React Native - The Native Side
Workshop 26: React Native - The Native Side
 
Workshop 25: React Native - Components
Workshop 25: React Native - ComponentsWorkshop 25: React Native - Components
Workshop 25: React Native - Components
 
Workshop 24: React Native Introduction
Workshop 24: React Native IntroductionWorkshop 24: React Native Introduction
Workshop 24: React Native Introduction
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Workshop 22: ReactJS Redux Advanced
Workshop 22: ReactJS Redux AdvancedWorkshop 22: ReactJS Redux Advanced
Workshop 22: ReactJS Redux Advanced
 
Workshop 22: React-Redux Middleware
Workshop 22: React-Redux MiddlewareWorkshop 22: React-Redux Middleware
Workshop 22: React-Redux Middleware
 
Workshop 21: React Router
Workshop 21: React RouterWorkshop 21: React Router
Workshop 21: React Router
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
Workshop 18: CSS Animations & cool effects
Workshop 18: CSS Animations & cool effectsWorkshop 18: CSS Animations & cool effects
Workshop 18: CSS Animations & cool effects
 
Workshop 17: EmberJS parte II
Workshop 17: EmberJS parte IIWorkshop 17: EmberJS parte II
Workshop 17: EmberJS parte II
 
Workshop 16: EmberJS Parte I
Workshop 16: EmberJS Parte IWorkshop 16: EmberJS Parte I
Workshop 16: EmberJS Parte I
 
Workshop 11: Trendy web designs & prototyping
Workshop 11: Trendy web designs & prototypingWorkshop 11: Trendy web designs & prototyping
Workshop 11: Trendy web designs & prototyping
 
Workshop 6: Designer tools
Workshop 6: Designer toolsWorkshop 6: Designer tools
Workshop 6: Designer tools
 
Workshop 4: NodeJS. Express Framework & MongoDB.
Workshop 4: NodeJS. Express Framework & MongoDB.Workshop 4: NodeJS. Express Framework & MongoDB.
Workshop 4: NodeJS. Express Framework & MongoDB.
 

Dernier

%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 

Dernier (20)

WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
WSO2CON 2024 Slides - Unlocking Value with AI
WSO2CON 2024 Slides - Unlocking Value with AIWSO2CON 2024 Slides - Unlocking Value with AI
WSO2CON 2024 Slides - Unlocking Value with AI
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
WSO2Con2024 - From Blueprint to Brilliance: WSO2's Guide to API-First Enginee...
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 

Workshop 5: JavaScript testing

  • 1. Front End Workshops VI.JavaScript testing. Client vs. Server testing. Test Driven Development Raúl Delgado Astudillo rdelgado@visual-engin.com Mario García Martín mgarcia@visual-engin.com
  • 2. JavaScript testing “Testing is an infinite process of comparing the invisible to the ambiguous in order to avoid the unthinkable happening to the anonymous.” — James Bach
  • 3. What is a test? Type some code Open and load the browser Prove functionality A test is (simply) the validation of an expectation. Manual testing... ...is NOT enough!
  • 4. Can we do better? Manual testing is... Time consuming Error prone Irreproducible (Nearly) Impossible if we want to test a wide set of browsers and platforms YES!! Automated testing
  • 5. Tests should be Fast to run Easy to understand Isolated Not reliant on an Internet connection
  • 6. Benefits and pitfalls of testing Regression testing Refactoring Cross-browser testing Good documentation Helps us write cleaner interfaces (testable code) Writing good tests can be challenging
  • 7. More information in... ● Test-Driven JavaScript Development, by Christian Johansen ● https://en.wikipedia.org/wiki/Software_testing
  • 8. Client testing “A passing test doesn't mean no problem. It means no problem observed. This time. With these inputs. So far. On my machine.” — Michael Bolton
  • 10. Jasmine — Scaffolding describe("A suite with setup and tear-down", function() { var foo; beforeAll(function() {}); afterAll(function() {}); beforeEach(function() { foo = 1; }); afterEach(function() { foo = 0; }); it("can contain specs with one or more expectations", function() { expect(foo).toBe(1); expect(true).toBe(true); }); });
  • 11. Matchers expect(3).toBe(3); // Compares with === expect({a: 3}).toEqual({a: 3}); // For comparison of objects expect('barely').toMatch(/bar/); // For regular expressions expect(null).toBeDefined(); // Compares against undefined expect(undefined).toBeUndefined(); // Compares against undefined expect(null).toBeNull(); // Compares against null expect('hello').toBeTruthy(); // For boolean casting testing expect('').toBeFalsy(); // For boolean casting testing expect(['bar', 'foo']).toContain('bar'); // For finding an item in an Array expect(2).toBeLessThan(3); // For mathematical comparisons expect(3).toBeGreaterThan(2); // For mathematical comparisons expect(3.14).toBeCloseTo(3.17, 1); // For precision math comparison // For testing if a function throws an exception expect(function() { throw new Error('Error!'); }).toThrow(); // Modifier 'not' expect(false).not.toBe(true);
  • 12. Spies describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456, 'another param'); }); it("that defines a spy out of the box", function() { expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called // tracks all the arguments of its calls expect(foo.setBar).toHaveBeenCalledWith(123); expect(foo.setBar).toHaveBeenCalledWith(456, 'another param'); expect(bar).toBeNull(); // stops all execution on a function }); });
  • 13. Spies — and.callthrough describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar').and.callThrough(); foo.setBar(123); }); it("that defines a spy configured to call through", function() { expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called expect(bar).toEqual(123); // the spied function has been called }); });
  • 14. describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { getBar: function() { return bar; } }; spyOn(foo, 'getBar').and.returnValue(745); }); it("that defines a spy configured to fake a return value", function() { expect(foo.getBar()).toBe(745); // when called returns the requested value expect(bar).toBeNull(); // should not affect the variable }); }); Spies — and.returnValue
  • 15. describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar').and.callFake(function() { console.log('hello'); }); foo.setBar(); // logs hello in the console. }); it("that defines a spy configured with an alternate implementation", function() { expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called expect(bar).toBeNull(); // should not affect the variable }); }); Spies — and.callFake
  • 16. Spies — createSpy describe("A suite", function() { var spy; beforeAll(function() { $(window).on('resize', function() { $(window).trigger('myEvent'); }); }); afterAll(function() { $(window).off('resize'); }); beforeEach(function() { spy = jasmine.createSpy(); }); it("that defines a spy created manually", function() { $(window).on('myEvent', spy); $(window).trigger('resize'); expect(spy).toHaveBeenCalled(); // tracks that the spy was called }); });
  • 17. Spies — Other tracking properties (I) describe("A spy", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456, 'baz'); }); it("has a rich set of tracking properties", function() { expect(foo.setBar.calls.count()).toEqual(2); // tracks the number of calls // tracks the args of each call expect(foo.setBar.calls.argsFor(0)).toEqual([123]); expect(foo.setBar.calls.argsFor(1)).toEqual([456, 'baz']); // has shortcuts to the first and most recent call expect(foo.setBar.calls.first().args).toEqual([123]); expect(foo.setBar.calls.mostRecent().args).toEqual([456, 'baz']); }); });
  • 18. Spies — Other tracking properties (II) describe("A spy", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456, 'baz'); }); it("has a rich set of tracking properties", function() { // tracks the context and return values expect(foo.setBar.calls.first().object).toEqual(foo); expect(foo.setBar.calls.first().returnValue).toBeUndefined(); // can be reset foo.setBar.calls.reset(); expect(foo.setBar.calls.count()).toBe(0); }); });
  • 19. Asynchronous support describe("Asynchronous specs", function() { var value; beforeEach(function(done) { setTimeout(function() { value = 0; done(); }, 100); }); it("should support async execution of preparation and expectations", function(done) { expect(value).toBe(0); done(); }); });
  • 20. Clock describe("Manually ticking the Jasmine Clock", function() { var timerCallback; beforeEach(function() { timerCallback = jasmine.createSpy(); jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it("causes a timeout to be called synchronously", function() { setTimeout(timerCallback, 100); expect(timerCallback).not.toHaveBeenCalled(); jasmine.clock().tick(101); expect(timerCallback).toHaveBeenCalled(); }); });
  • 21. Clock — Mocking the date describe("Mocking the Date object", function() { beforeEach(function() { jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it("mocks the Date object and sets it to a given time", function() { var baseTime = new Date(2013, 9, 23); jasmine.clock().mockDate(baseTime); jasmine.clock().tick(50); expect(new Date().getTime()).toEqual(baseTime.getTime() + 50); }); });
  • 22. Sinon — Spies and Stubs var spy = sinon.spy(); sinon.spy($, 'ajax'); $.ajax.restore(); sinon.stub($, 'ajax'); $.ajax.restore(); sinon.stub($, 'ajax', function(options) { console.log(options.url); }); $.ajax.restore();
  • 23. Sinon — Fake timer describe("Manually ticking the Clock", function() { var clock, timerCallback; beforeEach(function() { timerCallback = sinon.spy(); clock = sinon.useFakeTimers(); }); afterEach(function() { clock.restore(); }); it("causes a timeout to be called synchronously", function() { setTimeout(timerCallback, 100); expect(timerCallback.callCount).toBe(0); clock.tick(101); expect(timerCallback.callCount).toBe(1); expect(new Date().getTime()).toBe(101); }); });
  • 24. Sinon — Fake server describe("A suite with a sinon fakeServer", function() { var server; beforeEach(function() { server = sinon.fakeServer.create(); server.autoRespond = true; server.respondWith(function(xhr) { xhr.respond(200, {'Content-Type':'application/json'}, JSON.stringify({'msg': 'msg'})); }); server.xhr.useFilters = true; server.xhr.addFilter(function(method, url) { return !!url.match(/fixtures|css/); // If returns true the request will not be faked. }); }); afterEach(function() { server.restore(); }); });
  • 25. More information in... ● https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#JavaScri pt ● http://stackoverflow.com/questions/300855/javascript-unit-test-tools- for-tdd ● http://jasmine.github.io/ ● http://sinonjs.org/
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37. Test Driven Development “The best TDD can do is assure that the code does what the programmer thinks it should do. That is pretty good by the way.” — James Grenning
  • 38. The cycle of TDD Write a test Run tests. Watch the new test fail Make the test pass Refactor to remove duplication
  • 39. Benefits of TDD Produces code that works Honors the Single Responsibility Principle Forces conscious development Productivity boost
  • 40. More information in... ● Test-Driven Development By Example, by Kent Beck.
  • 41. Jasmine Disabling specs xdescribe("A disabled suite", function() { it("where the specs will not be executed", function() { expect(2).toEqual(1); }); }); describe("A suite", function() { xit("with a disabled spec declared with 'xit'", function() { expect(true).toBe(false); }); it.only("with a spec that will be executed", function() { expect(1).toBe(1); }); it("with another spec that will not be executed", function() { expect(1).toBe(1); }); });
  • 42. Asynchronous support describe("long asynchronous specs", function() { beforeEach(function(done) { done(); }, 1000); afterEach(function(done) { done(); }, 1000); it("takes a long time", function(done) { setTimeout(done, 9000); }, 10000); });
  • 43. Asynchronous support. Jasmine 1.3 describe("Asynchronous specs", function() { var value, flag; it("should support async execution of test preparation and expectations", function() { flag = false; value = 0; setTimeout(function() { flag = true; }, 500); waitsFor(function() { value++; return flag; }, "The Value should be incremented", 750); runs(function() { expect(value).toBeGreaterThan(0); }); }); });
  • 44. jasmine.Clock v.1.3 it('description', function() { jasmine.Clock.useMock(); setTimeout(function() { console.log('print something'); }, 200); jasmine.Clock.tick(190); }); it('description', function() { jasmine.Clock.useMock(); jasmine.Clock.tick(190); });
  • 45. Karma npm install karma --save-dev npm install karma-jasmine karma-chrome-launcher karma-phantomjs-launcher --save-dev npm install karma-coverage --save-dev npm install -g karma-cli Installation Configuration karma init karma.conf.js npm install grunt-karma --save-dev grunt.loadNpmTasks('grunt-karma'); karma: { unit: { configFile: 'karma.conf.js' } } Grunt task
  • 46. Karma configuration The files array determines which files are included in the browser and which files are watched and served by Karma. Each pattern is either a simple string or an object with four properties: pattern String, no default value. The pattern to use for matching. This property is mandatory. watched Boolean (true). If autoWatch is true all files that have set watched to true will be watched for changes. included Boolean (true). Should the files be included in the browser using <script> tag? Use false if you want to load them manually, eg. using Require.js. served Boolean (true). Should the files be served by Karma's webserver?
  • 47. THANKS FOR YOUR ATTENTION Leave your questions on the comments section