SlideShare una empresa de Scribd logo
1 de 96
Descargar para leer sin conexión
Mocha First Steps
Installing and running tests
Agenda
• JS Unit Testing	

• A first Mocha test	

• Running tests with Karma	

• IDE integration
Getting Ready To Test
• JS Unit tests (try) make sure our JS code
works well
Project Tree
index.html
 
- src
  - main.js
  - buttons.js
  - player.js
 
- style
  - master.css
  - home.css
 
Project Tree
index.html
test.html
 
- src
  - main.js
  - buttons.js
  - player.js
 
- style
  - master.css
  - home.css
 
- spec
  - test_button.js
  - test_player.js
What Mocha Isn’t
• No UI / CSS testing 	

• No server testing
Testing How
Testing Libraries
• Let’s try to write test program for Array	

• Verify indexOf(...) actually works
Array#indexof
var arr1 = [10, 20, 30, 40];
 
if ( arr1.indexOf(20) === 1 ) {
  console.log('success!');
} else {
  console.log('error');
}
What Went Wrong
• Hard to debug	

• Hard to run automatically
We Need …
We Need …
Testing Libraries
• A testing library tells you how to structure
your testing code	


• We’ll use mocha


http://visionmedia.github.io/mocha/
Hello Mocha
var assert = chai.assert;
var array = [10,20,30,40];
 
describe('Array', function() {
!
  describe('#indexOf()', function() {
!
    it('should return -1 when the value is not present',
function() {      
     
assert.equal(array.indexOf(7), -1);
   
}
);
  });
});
Hello Mocha
• describe() defines a block	

• it() defines functionality
Assertions

•

Uses a separate assertions
library	


•
•

I went with Chai	

http://chaijs.com/
Running Our Test:
Karma
Meet Karma
• A test runner for JS	

• Integrates with many IDEs	

• Integrates with CI servers	

• http://karma-runner.github.io/0.10/
index.html
Karma Architecture
Karma
Server
Karma Getting Started
# run just once to install
npm install karma -g
 
# create a project directory
mkdir myproject
cd myproject
 
# create karma configuration file
karma init
Karma Config
• Just a JavaScript file	

• keys determine how test should run
Karma Config
• files is a list of JS files to include in the test	

• Can use wildcards
Karma Config
• browsers is a list of supported browsers
Running Tests
# start a karma server
karma start
 
# execute tests
karma run
IDE Integration
What We Learned
• Mocha is a JS library that helps us write
unit tests	


• Karma is a JS library that helps us run them
Q &A
Advanced Mocha
How to write awesome tests
Agenda
• Flow control: before, after, beforeEach,
afterEach	


• Writing async tests	

• Fixtures and DOM testing
Let’s Flow
describe('Test 1', function() {
  it('should do X', function() {
    var p1 = new Player('bob');
    var p2 = new Player('John');
    var game = new GameEngine(p1, p2);
 
    // test stuff with game
  });
 
  it('should do Y', function() {
    var p1 = new Player('bob');
    var p2 = new Player('John');
    var game = new GameEngine(p1, p2);
 
    // test stuff with game
  });
});
Let’s Flow
describe('Test 1', function() {
  it('should do X', function() {
    var p1 = new Player('bob');
    var p2 = new Player('John');
    var game = new GameEngine(p1, p2);
 
    // test stuff with game
  });
 
  it('should do Y', function() {
    var p1 = new Player('bob');
    var p2 = new Player('John');
    var game = new GameEngine(p1, p2);
 
    // test stuff with game
  });
});

Same code...
A Better Scheme
•

beforeEach() runs
before each test	


•

also has:	


•
•

afterEach() for
cleanups	


describe('Test 1', function() {!
  var game;!
 !
  beforeEach(function() {!
    var p1 = new Player('bob');!
    var p2 = new Player('John');!
    game = new GameEngine(p1, p2);!
  });!
 !
  it('should do X', function() {!
    // test stuff with game!
  });!

!

before() and
after() run once
in the suite

 !
  it('should do Y', function() {!
    // test stuff with game!
  });!
});
Async Testing
Async Theory
var x = 10
test x

x has the right value	

testing here is OK
Async Theory
$.get(...)
test result

Can’t test now, 	

result not yet ready
Async Theory
• Async calls take callbacks	

• We should tell mocha to wait
Async Code
describe('Test 1', function() {
 
  it('should do wait', function(done) {
    setTimeout(function() {
      // now we can test result
      assert(true);
      done();
    }, 1000);
  });
 
});
Async Code
Taking a function
argument tells
mocha the test will
only end after it’s
called

describe('Test 1', function() {
 
  it('should do wait', function(done) {
    setTimeout(function() {
      // now we can test result
      assert(true);
      done();
    }, 1000);
  });
 
});
Async Code
Calling the callback
ends the test

describe('Test 1', function() {
 
  it('should do wait', function(done) {
    setTimeout(function() {
      // now we can test result
      assert(true);
      done();
    }, 1000);
  });
 
});
Async Notes
• Always call done() or your test will fail on
timeout	


• Default timeout is 2 seconds
Controlling Timeouts
describe('Test 1', function() {
  // set suite specific timeout
  this.timeout(500);
 
  it('should do wait', function(done) {
    // test specific timeout
    this.timeout(2000);    
  });
});
Same goes for Ajax
describe('Test 1', function() {
  // set suite specific timeout
  this.timeout(5000);
 
  it('should get user photo', function(done) {
    $.get('profile.png', function(data) {
      // run tests on data
      done();
    });
  });
});
DOM Testing
Theory
“Real” HTML
body
h1
div

body
img

div

“Test” HTML
Theory
“Real” HTML
body
h1
div

body
img

div

“Test” HTML

img
Theory
images.js
$('img.thumbnail').css({
width: 200,
height: 200
});

fixture.html
<img class="thumbmail" src="home.png" />
Using Fixtures
before(function() {
fixture_el = document.createElement('div');
fixture_el.id = "fixture";
!
document.body.appendChild(fixture_el);
});
!
beforeEach(function() {
fixture_el.innerHTML = window.__html__["fixture.html"];
});
!
Almost Ready
• HTML files are not served by default	

• We need to tell karma to serve it
Serving HTMLs
• Modify files section to include the last
(HTML) pattern

// list of files / patterns to load in the browser
files: [
'lib/**/*.js',
'plugins/**/*.js',
'test/fixtures/*.html',
'spec/*.js'
],
Testing a jQuery Plugin
it('should change the header text lowercase', function() {
$('.truncate').succinct({ size: 100 });
!
var result = $('.truncate').text();
assert.equal( result.length , 100 );
});
Fixtures & DOM
• Define DOM fragments in HTML files	

• Load from test suite	

• Test and clean up
Spying With Sinon
Stubs, Spies and Mock Objects explained
Agenda
• Reasons to mock	

• Vanilla mocking	

• How sinon can help	

• Stubs and Spies	

• Faking timers	

• Faking the server
Reasons To Mock
Reasons To Mock
$.ajax

setTimeout
PersonalData
Reasons To Mock
$.ajax

setTimeout
PersonalData
Reasons To Mock
• PersonalData object can save data to
server	


• If saving failed, it retries 3 times
Reasons To Mock
• Both server and clock are external	

• We prefer to test in isolation
What We Can Do
• Provide our own $.ajax, that won’t go to
the server	


• Provide our own setTimeout that won’t
wait for the time to pass
What We Can Do
• Lab: Given the class here


https://gist.github.com/ynonp/6667146	


• Write a test case to verify sendData
actually retried 3 times
What We Can Do
• Solution:


https://gist.github.com/ynonp/6667284
Mocking Notes
• Solution is far from perfect. 	

• After the test our “fake” methods remain	

• Writing “fake” methods was not trivial
This Calls for Sinon
About Sinon
• A JS mocking library	

• Helps create fake objects	

• Helps tracking them
About Sinon
• Homepage:


http://sinonjs.org/	


• Google Group:


http://groups.google.com/group/sinonjs	


• IRC Channel:


#sinon.js on freenode
Solving with Sinon
• Here’s how sinon might help us with the
previous task	


• Code:


https://gist.github.com/ynonp/6667378
Solution Notes
• Sinon’s fake timer was easier to use than
writing our own	


• Now we have a synchronous test (instead
of async)
Let’s Talk About Sinon
Spies
• A spy is a function that provides the test
code with info about how it was used
Spies Demo
describe('Sinon', function() {
describe('spies', function() {

!
!
!
!
!

it('should keep count', function() {
var s = sinon.spy();
s();
assert.isTrue(s.calledOnce);
s();
assert.isTrue(s.calledTwice);
s();
assert.equal(s.callCount, 3);

});
});
});
Spy On Existing Funcs
describe('Sinon', function() {
describe('spies', function() {
!
it('should keep count', function() {
var p = new PersonalData();
var spy = sinon.spy(p, 'sendData');
!
p.sendData();
!
assert.isTrue( spy.calledOnce );
});
});
});
Spies Notes
• Full API:


http://sinonjs.org/docs/#spies	


• Tip: Use as callbacks
Spy + Action = Stub
Stub Demo
• Let’s fix our starting example	

• We’ll replace $.ajax with a stub	

• That stub always fails
Stub Demo
var stub = sinon.stub(jQuery, 'ajax').yieldsTo('error');
!
describe('Data', function() {
describe('#sendData()', function() {
!
it('should retry 3 times before quitting', function() {
var p = new PersonalData();
p.sendData();
assert.equal(stub.callCount, 1);
});
});
});
What Can Stubs Do
var callback = sinon.stub();
!
callback.withArgs(42).returns(1);
!
callback.withArgs(1).throws("TypeError");
!
Stubs API
• Full Stubs API docs:


http://sinonjs.org/docs/#stubs	


• Main actions:	

• return stuff	

• throw stuff	

• call stuff
Spies Lab
• Given code here:


https://gist.github.com/ynonp/7101081	


• Fill in the blanks to make the tests pass
Fake Timers
• Use sinon.useFakeTimers() to create a
fake timer	


• Use clock.restore() to clear fake timers
Fake Timers
• Use tick(...) to advance	

• Affected methods:	

• setTimeout, setInterval, clearTimeout,
clearInterval	


• Date constructor
Fake Servers
• Testing client/server communication is hard	

• Use fake servers to simplify it
Fake Servers
$.ajax

PersonalData
Fake Servers
Fake

$.ajax

PersonalData
Let’s write a test for the following class
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.

function Person(id) {
  var self = this;
 
  self.load = function() {
    var url = '/users/' + id;
 
    $.get('/users/' + id, function(info) {
      self.name = info.name;
      self.favorite_color = info.favorite_color;
    });
  };
}
Testing Plan
• Set-up a fake server	

• Create a new Person	

• call load()	

• verify fields data
Setting Up The Server
1.
2.
3.
4.
5.
6.
7.
8.
9.

var server = sinon.fakeServer.create();
 
var headers  = {"Content-Type" : "application/json"};
var response = JSON.stringify(
                {"name" : "joe", "favorite_color": "blue" });
 
server.respondWith("GET", "/users/7",
                   [200, headers, response]);
// now requesting /user/info.php returns joe's info as a JSON
Loading a Person
1.
2.
3.
4.
5.
6.

var p = new Person(7);
// sends a request
p.load();
 
// now we have 1 pending request, let's fake the response
server.respond();
Verifying the Data
1.
2.
3.
4.
5.
6.

// finally, verify data
expect(p.name).to.eq('joe');
expect(p.favorite_color).to.eq('blue');
 
// and restore AJAX behavior
server.restore();
Fake Server
• Use respondWith() to set up routes	

• Use respond() to send the response
Fake Server
• Regexps are also supported, so this works:
1.
2.
3.
4.
5.
6.

server.respondWith(//todo-items/(d+)/, function (xhr, id) {
    xhr.respond(
      200,
      { "Content-Type": "application/json" },
      '[{ "id": ' + id + ' }]');
});
Fake Server
• For fine grained control, consider fake
XMLHttpRequest 	


• http://sinonjs.org/docs/#server
Wrapping Up
Wrapping Up
• Unit tests work best in isolation	

• Sinon will help you isolate units, by faking
their dependencies
Wrapping Up
• Write many tests	

• Each test verifies a small chunk of code	

• Don’t test everything
Online Resources

• Chai:


http://chaijs.com/	


• Mocha:


http://visionmedia.github.io/mocha/	


• Sinon:


http://sinonjs.org/	


• Karma (test runner):


http://karma-runner.github.io/0.10/index.html
Thanks For Listening
• Ynon Perek	

• http://ynonperek.com	

• ynon@ynonperek.com

Más contenido relacionado

La actualidad más candente

Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
Ran Mizrahi
 

La actualidad más candente (20)

Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyJasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishy
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with Karma
 
Javascript Test Automation Workshop (21.08.2014)
Javascript Test Automation Workshop (21.08.2014)Javascript Test Automation Workshop (21.08.2014)
Javascript Test Automation Workshop (21.08.2014)
 
Test-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS ApplicationsTest-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS Applications
 
Advanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingAdvanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit Testing
 
Angularjs - Unit testing introduction
Angularjs - Unit testing introductionAngularjs - Unit testing introduction
Angularjs - Unit testing introduction
 
Angular testing
Angular testingAngular testing
Angular testing
 
Javascript Testing with Jasmine 101
Javascript Testing with Jasmine 101Javascript Testing with Jasmine 101
Javascript Testing with Jasmine 101
 
Painless JavaScript Testing with Jest
Painless JavaScript Testing with JestPainless JavaScript Testing with Jest
Painless JavaScript Testing with Jest
 
Quick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmineQuick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmine
 
JavaScript TDD with Jasmine and Karma
JavaScript TDD with Jasmine and KarmaJavaScript TDD with Jasmine and Karma
JavaScript TDD with Jasmine and Karma
 
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
 
Unit tests in node.js
Unit tests in node.jsUnit tests in node.js
Unit tests in node.js
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSIntro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJS
 
Unit testing in JavaScript with Jasmine and Karma
Unit testing in JavaScript with Jasmine and KarmaUnit testing in JavaScript with Jasmine and Karma
Unit testing in JavaScript with Jasmine and Karma
 
Testing JavaScript Applications
Testing JavaScript ApplicationsTesting JavaScript Applications
Testing JavaScript Applications
 
Unit Testing Express Middleware
Unit Testing Express MiddlewareUnit Testing Express Middleware
Unit Testing Express Middleware
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJS
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
 
Сергей Больщиков "Protractor Tips & Tricks"
Сергей Больщиков "Protractor Tips & Tricks"Сергей Больщиков "Protractor Tips & Tricks"
Сергей Больщиков "Protractor Tips & Tricks"
 

Similar a Unit Testing JavaScript Applications

In search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testingIn search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testing
Anna Khabibullina
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Robot Media
 

Similar a Unit Testing JavaScript Applications (20)

Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
 
Java script unit testing
Java script unit testingJava script unit testing
Java script unit testing
 
Testing Ext JS and Sencha Touch
Testing Ext JS and Sencha TouchTesting Ext JS and Sencha Touch
Testing Ext JS and Sencha Touch
 
Performance patterns
Performance patternsPerformance patterns
Performance patterns
 
Quick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmineQuick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmine
 
Jest: Frontend Testing richtig gemacht @WebworkerNRW
Jest: Frontend Testing richtig gemacht @WebworkerNRWJest: Frontend Testing richtig gemacht @WebworkerNRW
Jest: Frontend Testing richtig gemacht @WebworkerNRW
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and HowsUnit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Hows
 
Testing ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NETTesting ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NET
 
UI Testing Best Practices - An Expected Journey
UI Testing Best Practices - An Expected JourneyUI Testing Best Practices - An Expected Journey
UI Testing Best Practices - An Expected Journey
 
SwampDragon presentation: The Copenhagen Django Meetup Group
SwampDragon presentation: The Copenhagen Django Meetup GroupSwampDragon presentation: The Copenhagen Django Meetup Group
SwampDragon presentation: The Copenhagen Django Meetup Group
 
Full Stack Unit Testing
Full Stack Unit TestingFull Stack Unit Testing
Full Stack Unit Testing
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Awesomeness of JavaScript…almost
Awesomeness of JavaScript…almostAwesomeness of JavaScript…almost
Awesomeness of JavaScript…almost
 
In search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testingIn search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testing
 
NodeJS
NodeJSNodeJS
NodeJS
 
Describe's Full of It's
Describe's Full of It'sDescribe's Full of It's
Describe's Full of It's
 
Node.js Development Workflow Automation with Grunt.js
Node.js Development Workflow Automation with Grunt.jsNode.js Development Workflow Automation with Grunt.js
Node.js Development Workflow Automation with Grunt.js
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
Java Performance Tuning
Java Performance TuningJava Performance Tuning
Java Performance Tuning
 
CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!CBDW2014 - MockBox, get ready to mock your socks off!
CBDW2014 - MockBox, get ready to mock your socks off!
 

Más de Ynon Perek

Mobile Devices
Mobile DevicesMobile Devices
Mobile Devices
Ynon Perek
 

Más de Ynon Perek (20)

Regexp
RegexpRegexp
Regexp
 
Html5 intro
Html5 introHtml5 intro
Html5 intro
 
09 performance
09 performance09 performance
09 performance
 
Mobile Web Intro
Mobile Web IntroMobile Web Intro
Mobile Web Intro
 
Qt multi threads
Qt multi threadsQt multi threads
Qt multi threads
 
Vimperl
VimperlVimperl
Vimperl
 
Syllabus
SyllabusSyllabus
Syllabus
 
Mobile Devices
Mobile DevicesMobile Devices
Mobile Devices
 
Network
NetworkNetwork
Network
 
Architecture app
Architecture appArchitecture app
Architecture app
 
Cryptography
CryptographyCryptography
Cryptography
 
How to write easy-to-test JavaScript
How to write easy-to-test JavaScriptHow to write easy-to-test JavaScript
How to write easy-to-test JavaScript
 
Introduction to Selenium and Ruby
Introduction to Selenium and RubyIntroduction to Selenium and Ruby
Introduction to Selenium and Ruby
 
Introduction To Web Application Testing
Introduction To Web Application TestingIntroduction To Web Application Testing
Introduction To Web Application Testing
 
Accessibility
AccessibilityAccessibility
Accessibility
 
Angularjs
AngularjsAngularjs
Angularjs
 
Js memory
Js memoryJs memory
Js memory
 
Qt Design Patterns
Qt Design PatternsQt Design Patterns
Qt Design Patterns
 
Web Application Security
Web Application SecurityWeb Application Security
Web Application Security
 
JavaScript DOM Manipulations
JavaScript DOM ManipulationsJavaScript DOM Manipulations
JavaScript DOM Manipulations
 

Último

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Último (20)

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 

Unit Testing JavaScript Applications

  • 1. Mocha First Steps Installing and running tests
  • 2. Agenda • JS Unit Testing • A first Mocha test • Running tests with Karma • IDE integration
  • 3. Getting Ready To Test • JS Unit tests (try) make sure our JS code works well
  • 4. Project Tree index.html   - src   - main.js   - buttons.js   - player.js   - style   - master.css   - home.css  
  • 5. Project Tree index.html test.html   - src   - main.js   - buttons.js   - player.js   - style   - master.css   - home.css   - spec   - test_button.js   - test_player.js
  • 6. What Mocha Isn’t • No UI / CSS testing • No server testing
  • 8. Testing Libraries • Let’s try to write test program for Array • Verify indexOf(...) actually works
  • 9. Array#indexof var arr1 = [10, 20, 30, 40];   if ( arr1.indexOf(20) === 1 ) {   console.log('success!'); } else {   console.log('error'); }
  • 10. What Went Wrong • Hard to debug • Hard to run automatically
  • 13. Testing Libraries • A testing library tells you how to structure your testing code • We’ll use mocha
 http://visionmedia.github.io/mocha/
  • 14. Hello Mocha var assert = chai.assert; var array = [10,20,30,40];   describe('Array', function() { !   describe('#indexOf()', function() { !     it('should return -1 when the value is not present', function() {             assert.equal(array.indexOf(7), -1);     } );   }); });
  • 15. Hello Mocha • describe() defines a block • it() defines functionality
  • 16. Assertions • Uses a separate assertions library • • I went with Chai http://chaijs.com/
  • 18. Meet Karma • A test runner for JS • Integrates with many IDEs • Integrates with CI servers • http://karma-runner.github.io/0.10/ index.html
  • 20. Karma Getting Started # run just once to install npm install karma -g   # create a project directory mkdir myproject cd myproject   # create karma configuration file karma init
  • 21. Karma Config • Just a JavaScript file • keys determine how test should run
  • 22. Karma Config • files is a list of JS files to include in the test • Can use wildcards
  • 23. Karma Config • browsers is a list of supported browsers
  • 24. Running Tests # start a karma server karma start   # execute tests karma run
  • 26. What We Learned • Mocha is a JS library that helps us write unit tests • Karma is a JS library that helps us run them
  • 27. Q &A
  • 28. Advanced Mocha How to write awesome tests
  • 29. Agenda • Flow control: before, after, beforeEach, afterEach • Writing async tests • Fixtures and DOM testing
  • 30. Let’s Flow describe('Test 1', function() {   it('should do X', function() {     var p1 = new Player('bob');     var p2 = new Player('John');     var game = new GameEngine(p1, p2);       // test stuff with game   });     it('should do Y', function() {     var p1 = new Player('bob');     var p2 = new Player('John');     var game = new GameEngine(p1, p2);       // test stuff with game   }); });
  • 31. Let’s Flow describe('Test 1', function() {   it('should do X', function() {     var p1 = new Player('bob');     var p2 = new Player('John');     var game = new GameEngine(p1, p2);       // test stuff with game   });     it('should do Y', function() {     var p1 = new Player('bob');     var p2 = new Player('John');     var game = new GameEngine(p1, p2);       // test stuff with game   }); }); Same code...
  • 32. A Better Scheme • beforeEach() runs before each test • also has: • • afterEach() for cleanups describe('Test 1', function() {!   var game;!  !   beforeEach(function() {!     var p1 = new Player('bob');!     var p2 = new Player('John');!     game = new GameEngine(p1, p2);!   });!  !   it('should do X', function() {!     // test stuff with game!   });! ! before() and after() run once in the suite  !   it('should do Y', function() {!     // test stuff with game!   });! });
  • 34. Async Theory var x = 10 test x x has the right value testing here is OK
  • 35. Async Theory $.get(...) test result Can’t test now, result not yet ready
  • 36. Async Theory • Async calls take callbacks • We should tell mocha to wait
  • 37. Async Code describe('Test 1', function() {     it('should do wait', function(done) {     setTimeout(function() {       // now we can test result       assert(true);       done();     }, 1000);   });   });
  • 38. Async Code Taking a function argument tells mocha the test will only end after it’s called describe('Test 1', function() {     it('should do wait', function(done) {     setTimeout(function() {       // now we can test result       assert(true);       done();     }, 1000);   });   });
  • 39. Async Code Calling the callback ends the test describe('Test 1', function() {     it('should do wait', function(done) {     setTimeout(function() {       // now we can test result       assert(true);       done();     }, 1000);   });   });
  • 40. Async Notes • Always call done() or your test will fail on timeout • Default timeout is 2 seconds
  • 41. Controlling Timeouts describe('Test 1', function() {   // set suite specific timeout   this.timeout(500);     it('should do wait', function(done) {     // test specific timeout     this.timeout(2000);       }); });
  • 42. Same goes for Ajax describe('Test 1', function() {   // set suite specific timeout   this.timeout(5000);     it('should get user photo', function(done) {     $.get('profile.png', function(data) {       // run tests on data       done();     });   }); });
  • 47. Using Fixtures before(function() { fixture_el = document.createElement('div'); fixture_el.id = "fixture"; ! document.body.appendChild(fixture_el); }); ! beforeEach(function() { fixture_el.innerHTML = window.__html__["fixture.html"]; }); !
  • 48. Almost Ready • HTML files are not served by default • We need to tell karma to serve it
  • 49. Serving HTMLs • Modify files section to include the last (HTML) pattern // list of files / patterns to load in the browser files: [ 'lib/**/*.js', 'plugins/**/*.js', 'test/fixtures/*.html', 'spec/*.js' ],
  • 50. Testing a jQuery Plugin it('should change the header text lowercase', function() { $('.truncate').succinct({ size: 100 }); ! var result = $('.truncate').text(); assert.equal( result.length , 100 ); });
  • 51. Fixtures & DOM • Define DOM fragments in HTML files • Load from test suite • Test and clean up
  • 52. Spying With Sinon Stubs, Spies and Mock Objects explained
  • 53. Agenda • Reasons to mock • Vanilla mocking • How sinon can help • Stubs and Spies • Faking timers • Faking the server
  • 57. Reasons To Mock • PersonalData object can save data to server • If saving failed, it retries 3 times
  • 58. Reasons To Mock • Both server and clock are external • We prefer to test in isolation
  • 59. What We Can Do • Provide our own $.ajax, that won’t go to the server • Provide our own setTimeout that won’t wait for the time to pass
  • 60. What We Can Do • Lab: Given the class here
 https://gist.github.com/ynonp/6667146 • Write a test case to verify sendData actually retried 3 times
  • 61. What We Can Do • Solution:
 https://gist.github.com/ynonp/6667284
  • 62. Mocking Notes • Solution is far from perfect. • After the test our “fake” methods remain • Writing “fake” methods was not trivial
  • 63. This Calls for Sinon
  • 64. About Sinon • A JS mocking library • Helps create fake objects • Helps tracking them
  • 65. About Sinon • Homepage:
 http://sinonjs.org/ • Google Group:
 http://groups.google.com/group/sinonjs • IRC Channel:
 #sinon.js on freenode
  • 66. Solving with Sinon • Here’s how sinon might help us with the previous task • Code:
 https://gist.github.com/ynonp/6667378
  • 67. Solution Notes • Sinon’s fake timer was easier to use than writing our own • Now we have a synchronous test (instead of async)
  • 69. Spies • A spy is a function that provides the test code with info about how it was used
  • 70. Spies Demo describe('Sinon', function() { describe('spies', function() { ! ! ! ! ! it('should keep count', function() { var s = sinon.spy(); s(); assert.isTrue(s.calledOnce); s(); assert.isTrue(s.calledTwice); s(); assert.equal(s.callCount, 3); }); }); });
  • 71. Spy On Existing Funcs describe('Sinon', function() { describe('spies', function() { ! it('should keep count', function() { var p = new PersonalData(); var spy = sinon.spy(p, 'sendData'); ! p.sendData(); ! assert.isTrue( spy.calledOnce ); }); }); });
  • 72. Spies Notes • Full API:
 http://sinonjs.org/docs/#spies • Tip: Use as callbacks
  • 73. Spy + Action = Stub
  • 74. Stub Demo • Let’s fix our starting example • We’ll replace $.ajax with a stub • That stub always fails
  • 75. Stub Demo var stub = sinon.stub(jQuery, 'ajax').yieldsTo('error'); ! describe('Data', function() { describe('#sendData()', function() { ! it('should retry 3 times before quitting', function() { var p = new PersonalData(); p.sendData(); assert.equal(stub.callCount, 1); }); }); });
  • 76. What Can Stubs Do var callback = sinon.stub(); ! callback.withArgs(42).returns(1); ! callback.withArgs(1).throws("TypeError"); !
  • 77. Stubs API • Full Stubs API docs:
 http://sinonjs.org/docs/#stubs • Main actions: • return stuff • throw stuff • call stuff
  • 78. Spies Lab • Given code here:
 https://gist.github.com/ynonp/7101081 • Fill in the blanks to make the tests pass
  • 79. Fake Timers • Use sinon.useFakeTimers() to create a fake timer • Use clock.restore() to clear fake timers
  • 80. Fake Timers • Use tick(...) to advance • Affected methods: • setTimeout, setInterval, clearTimeout, clearInterval • Date constructor
  • 81. Fake Servers • Testing client/server communication is hard • Use fake servers to simplify it
  • 84. Let’s write a test for the following class 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. function Person(id) {   var self = this;     self.load = function() {     var url = '/users/' + id;       $.get('/users/' + id, function(info) {       self.name = info.name;       self.favorite_color = info.favorite_color;     });   }; }
  • 85. Testing Plan • Set-up a fake server • Create a new Person • call load() • verify fields data
  • 86. Setting Up The Server 1. 2. 3. 4. 5. 6. 7. 8. 9. var server = sinon.fakeServer.create();   var headers  = {"Content-Type" : "application/json"}; var response = JSON.stringify(                 {"name" : "joe", "favorite_color": "blue" });   server.respondWith("GET", "/users/7",                    [200, headers, response]); // now requesting /user/info.php returns joe's info as a JSON
  • 87. Loading a Person 1. 2. 3. 4. 5. 6. var p = new Person(7); // sends a request p.load();   // now we have 1 pending request, let's fake the response server.respond();
  • 88. Verifying the Data 1. 2. 3. 4. 5. 6. // finally, verify data expect(p.name).to.eq('joe'); expect(p.favorite_color).to.eq('blue');   // and restore AJAX behavior server.restore();
  • 89. Fake Server • Use respondWith() to set up routes • Use respond() to send the response
  • 90. Fake Server • Regexps are also supported, so this works: 1. 2. 3. 4. 5. 6. server.respondWith(//todo-items/(d+)/, function (xhr, id) {     xhr.respond(       200,       { "Content-Type": "application/json" },       '[{ "id": ' + id + ' }]'); });
  • 91. Fake Server • For fine grained control, consider fake XMLHttpRequest • http://sinonjs.org/docs/#server
  • 93. Wrapping Up • Unit tests work best in isolation • Sinon will help you isolate units, by faking their dependencies
  • 94. Wrapping Up • Write many tests • Each test verifies a small chunk of code • Don’t test everything
  • 95. Online Resources • Chai:
 http://chaijs.com/ • Mocha:
 http://visionmedia.github.io/mocha/ • Sinon:
 http://sinonjs.org/ • Karma (test runner):
 http://karma-runner.github.io/0.10/index.html
  • 96. Thanks For Listening • Ynon Perek • http://ynonperek.com • ynon@ynonperek.com