★How do I write Testable Javascript?
★Agenda ★Who Am I? ★State of the Room? ★Ways to test Javascript? ★Different Testing Environments? ★Overview of Testing Tools ★Using Testing in your Workflow ★Spaghetti Javascript ★Refactor Spaghetti into Testable Javascript ★Installing Jasmine + Live Demo
★Who Am I? ★Gavin Pickin – developing Web Apps since late 90s ○Ortus Solutions Software Consultant ○ContentBox Evangelist ★What else do you need to know? ○CFMLRepo.com http://www.cfmlrepo.com ○Blog - http://www.gpickin.com ○Twitter – http://twitter.com/gpickin ○Github - https://github.com/gpickin ★Lets get on with the show.
★State of the Room ★ A few questions for you guys ★ If you have arms, use them.
★State of the Room Testing? What’s testing?
★State of the Room Yeah, I’ve heard of it. Why do you think I’m here?
★State of the Room Yes I know I should be testing, but I’m not sure how to do it
★State of the Room My Boss and my Customers wouldn’t let me
★State of the Room I’m a tester
★State of the Room I’m a test writing ninja Call me Majano, Luis Majano
★Ways to Test your Code ★Click around in the browser yourself ★Setup Selenium / Web Driver to click around for you ★Structured Programmatic Tests
★Types of Testing
★Types of Testing ★Black/White Box ★Unit Testing ★Integration Testing ★Functional Tests ★System Tests ★End to End Tests ★Sanity Testing ★Regression Test ★Acceptance Tests ★Load Testing ★Stress Test ★Performance Tests ★Usability Tests ★+ More
★Levels of Testing
★Cost of a Bug The bug will cost one way or another
★Integration Testing
★Integration Testing ★Integration Tests several of the pieces together ★Most of the types of tests are variations of an Integration Test ★Can include mocks but can full end to end tests including DB / APIs
★Unit Testing
★Unit Testing “unit testing is a software verification and validation method in which a programmer tests if individual units of source code are fit for use. A unit is the smallest testable part of an application” - wikipedia
★Unit Testing ★Can improve code quality -> quick error discovery ★Code confidence via immediate verification ★Can expose high coupling ★Will encourage refactoring to produce > testable code ★Remember: Testing is all about behavior and expectations
★Styles – TDD vs BDD ★TDD = Test Driven Development ○Write Tests ○Run them and they Fail ○Write Functions to Fulfill the Tests ○Tests should pass ○Refactor in confidence ★Test focus on Functionality
★Styles – TDD vs BDD ★BDD = Behavior Driven Development Actually similar to TDD except: ★Focuses on Behavior and Specifications ★Specs (tests) are fluent and readable ★Readability makes them great for all levels of testing in the organization ★Hard to find TDD examples in JS that are not using BDD describe and it blocks
★TDD Example Test( ‘Email address must not be blank’, function(){ notEqual(email, “”, "failed"); });
★BDD Example Describe( ‘Email Address’, function(){ It(‘should not be blank’, function(){ expect(email).not.toBe(“”); }); });
★Matchers expect(true).toBe(true); expect(true).toBe(true); expect(true).toBe(true); expect(true).toBe(true);
★Matchers expect(true).not.toBe(true); expect(true).not.toBe(true); expect(true).not.toBe(true); expect(true).not.toBe(true); expect(true).not.toBe(true);
★Matcher Samples expect(true).toBe(true); expect(a).not.toBe(null); expect(a).toEqual(12); expect(message).toMatch(/bar/); expect(message).toMatch("bar"); expect(message).not.toMatch(/quux/); expect(a.foo).toBeDefined(); expect(a.bar).not.toBeDefined();
★Different Testing Environments? NodeJS - CLI In the Browser
★Overview of Testing Tools ★There are a few choices
★Main Testing Players ★Jasmine, Mocha and QUnit
★Jasmine ★Jasmine comes ready to go out of the box ★Fluent Syntax – BDD Style ★Includes lots of matchers ★Has spies included ★Very popular, lots of support ★Angular uses Jasmine with Karma (CLI) ★Headless running and plays well with CI servers
★Jasmine - Cons ★Async testing in 1.3 can be a headache ★Expects *spec.js suffix for test files ○This can be modified depending on how you are running the tests
★Jasmine – Sample Test describe("Hello world function", function() { it(”contains the word world", function() { expect(helloWorld()).toContain("world"); }); });
★Mocha★Simple Setup ★Simple Async testing ★Works great with other Assertion libraries like Chai ( not included ) ★Solid Support with CI Servers, with Plugins for others ★Opinion says Mocha blazing the trail for new features
★Mocha - Cons ★Requires other Libraries for key features ○No Assertion Library included ○No Mocking / Spied included ○Need to create the runner manually ★Newer to the game so not as popular or supported as others but gaining traction.
★Mocha – BDD Sample Test var expect = require('chai').expect; describe(’Hello World Function', function(){ it('should contain the word world', function(){ expect(helloWorld()).to.contain(’world'); }) })
★QUnit ★The oldest of the main testing frameworks ★Is popular due to use in jQuery and age ★Ember’s default Unit testing Framework
★QUnit - Cons ★Development slowed down since 2013 (but still under development) ★Syntax – No BDD style ★Assertion libraries – limited matchers
★QUnit – Sample Test QUnit.test( "ok test", function( assert ) { assert.ok( true, "true succeeds" ); assert.ok( "non-empty", "non-empty string succeeds" ); assert.ok( false, "false fails" ); assert.ok( 0, "0 fails" ); assert.ok( NaN, "NaN fails" ); assert.ok( "", "empty string fails" ); assert.ok( null, "null fails" ); assert.ok( undefined, "undefined fails" ); });
★Spaghetti Javascript Photo Credit – Kombination http://www.kombination.co.za/wp-content/uploads/2012/10/baby_w_spaghetti_mess_4987941.jpg
★Spaghetti Javascript Example If we have time at the end
★Spaghetti Javascript Example
★Refactoring Spaghetti ★Things to refactor to make your code testable ○Code should not be one big chunk of Javascript in onReady() ○Deep nested callbacks & Anon functions cannot easily be singled out and tested ○Remove Tight Coupling – DOM access for example
★Object Literals var personObjLit = { ssn: ’xxxxxxxx', age: '35', name: 'Gavin Pickin', getAge: function(){ return this.age; }, getName: function() { return this.name; } };
★Module Pattern var personObjLit2 = function() { ssn = ’xxxxxxx'; age = '35'; name = 'Gavin Pickin’; return { getAge: function(){ return age; }, getName: function() { return name; } }; };
★Using Testing in your Workflow ★Using HTML Test Runners ○Keep a Browser open ○F5 refresh tests
★Command Line Tests ★Run Jasmine – manual ○Run tests at the end of each section of work ★Run Grunt-Watch – automatic ○Runs Jasmine on every file change ○Grunt can run other tasks as well, minification etc
★Testing in your IDE ★Browser Views ○Eclipse allows you to open files in web view – uses HTML Runner ★Run Jasmine / Grunt / Karma in IDE Console ○Easy to setup – See Demo– Sublime Text 2
★Live Demo and Examples *Install / Run Jasmine Standalone for Browser *Install / Run Jasmine with NodeJs *Install/ Run Jasmine with Grunt Watch *Install / Run Grunt Watch inside Sublime Text 2
★Install / Run Jasmine for In- Browser Testing Download standalone package from Github (I have 2.1.3) https://github.com/jasmine/jasmine/tree/master/dist Unzip into your /tests folder Run /tests/SpecRunner.html to see example tests
★Standalone Jasmine
★Installing Jasmine for in Browser Testing
★SpecRunner Setup Jasmine Browser Test <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Jasmine Spec Runner v2.1.3</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.1.3/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-2.1.3/jasmine.css”> <script src="lib/jasmine-2.1.3/jasmine.js"></script> <script src="lib/jasmine-2.1.3/jasmine-html.js"></script> <script src="lib/jasmine-2.1.3/boot.js"></script> <!-- include source files here... --> <script src="../js/services/loginService.js"></script> <!-- include spec files here... --> <script src="spec/loginServiceSpec.js"></script> </head> <body> </body> </html>
★Installing Jasmine with NodeJS Assuming you have NodeJs Installed… install Jasmine $ npm install jasmine jasmine@2.2.1 node_modules/jasmine ├── exit@0.1.2 ├── jasmine-core@2.2.0 └── glob@3.2.11 (inherits@2.0.1, minimatch@0.3.0)
★Installing Jasmine with NodeJS Once Jasmine is installed in your project $ Jasmine init
★Installing Jasmine with NodeJS Edit Jasmine.json to update Locations for Spec Files and Helper Files { "spec_dir": "spec", "spec_files": [ "**/*[sS]pec.js" ], "helpers": [ "helpers/**/*.js" ] }
★Running Jasmine Tests with NodeJS$ Jasmine Started F Failures: 1) A suite contains spec with an expectation Message: Expected true to be false. Stack: Error: Expected true to be false. at Object.<anonymous> (/Users/gavinpickin/Dropbox/Apps/testApp/www/spec/test_spec.js:3: 18) 1 spec, 1 failure Finished in 0.009 seconds
★Running Jasmine Tests with NodeJS ★Jasmine-Node is great for Node ★Jasmine Node doesn’t have a headless browser ★Hard to test Browser code ★So what should I use?
★Installing Jasmine with Grunt Watcher ★Install Grunt npm install grunt ★Install Grunt – Jasmine npm install grunt-contrib-jasmine ★Install Grunt – Watch npm install grunt-contrib-watch ★Note: On Mac, I also needed to install Grunt CLI npm install –g grunt-cli
★Configuring Jasmine with Grunt Watcher // gruntfile.js - https://gist.github.com/gpickin/1e1e7902d1d3676d23c5 module.exports = function (grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('node_modules/grunt/package.json'), jasmine: { all: { src: ['js/*.js' ], options: { //'vendor': ['path/to/vendor/libs/*.js'], 'specs': ['specs/*.js' ] } } },
★Configuring Jasmine with Grunt Watcher // gruntfile.js part 2 watch: { js: { files: [ 'js/*.js', 'specs/*.js', ], tasks: ['jasmine:all'] } } });
★Configuring Jasmine with Grunt Watcher // gruntfile.js part 3 grunt.loadNpmTasks('grunt-contrib-jasmine'); grunt.loadNpmTasks('grunt-contrib-watch'); };
★Example Spec Jasmine with Grunt Watcher describe("A suite", function() { it("contains spec with an expectation", function() { expect(true).toBe(true); }); });
★Running Jasmine with Grunt Watcher
★Running Jasmine with Grunt Watcher
★Running in Sublime Text 2 ★Install PackageControl into Sublime Text ★Install Grunt from PackageControl ○https://packagecontrol.io/packages/Grunt ★Update Grunt Sublime Settings for paths { "exec_args": { "path": "/bin:/usr/bin:/usr/local/bin” } } ★Then Command Shift P – grunt
★Running in Sublime Text 2
★Refactoring Spaghetti ★Lets look at some code ★This isn’t BEST PRACTICE, its BETTER PRACTICE than you were doing ★Its not really refactoring if you don’t have tests, its “moving code and asking for trouble”
★Q&A ★Any questions?

How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016

  • 1.
    ★How do Iwrite Testable Javascript?
  • 2.
    ★Agenda ★Who Am I? ★Stateof the Room? ★Ways to test Javascript? ★Different Testing Environments? ★Overview of Testing Tools ★Using Testing in your Workflow ★Spaghetti Javascript ★Refactor Spaghetti into Testable Javascript ★Installing Jasmine + Live Demo
  • 3.
    ★Who Am I? ★GavinPickin – developing Web Apps since late 90s ○Ortus Solutions Software Consultant ○ContentBox Evangelist ★What else do you need to know? ○CFMLRepo.com http://www.cfmlrepo.com ○Blog - http://www.gpickin.com ○Twitter – http://twitter.com/gpickin ○Github - https://github.com/gpickin ★Lets get on with the show.
  • 4.
    ★State of theRoom ★ A few questions for you guys ★ If you have arms, use them.
  • 5.
    ★State of theRoom Testing? What’s testing?
  • 6.
    ★State of theRoom Yeah, I’ve heard of it. Why do you think I’m here?
  • 7.
    ★State of theRoom Yes I know I should be testing, but I’m not sure how to do it
  • 8.
    ★State of theRoom My Boss and my Customers wouldn’t let me
  • 9.
    ★State of theRoom I’m a tester
  • 10.
    ★State of theRoom I’m a test writing ninja Call me Majano, Luis Majano
  • 11.
    ★Ways to Testyour Code ★Click around in the browser yourself ★Setup Selenium / Web Driver to click around for you ★Structured Programmatic Tests
  • 12.
  • 13.
    ★Types of Testing ★Black/WhiteBox ★Unit Testing ★Integration Testing ★Functional Tests ★System Tests ★End to End Tests ★Sanity Testing ★Regression Test ★Acceptance Tests ★Load Testing ★Stress Test ★Performance Tests ★Usability Tests ★+ More
  • 14.
  • 15.
    ★Cost of aBug The bug will cost one way or another
  • 16.
  • 17.
    ★Integration Testing ★Integration Testsseveral of the pieces together ★Most of the types of tests are variations of an Integration Test ★Can include mocks but can full end to end tests including DB / APIs
  • 18.
  • 19.
    ★Unit Testing “unit testingis a software verification and validation method in which a programmer tests if individual units of source code are fit for use. A unit is the smallest testable part of an application” - wikipedia
  • 20.
    ★Unit Testing ★Can improvecode quality -> quick error discovery ★Code confidence via immediate verification ★Can expose high coupling ★Will encourage refactoring to produce > testable code ★Remember: Testing is all about behavior and expectations
  • 21.
    ★Styles – TDDvs BDD ★TDD = Test Driven Development ○Write Tests ○Run them and they Fail ○Write Functions to Fulfill the Tests ○Tests should pass ○Refactor in confidence ★Test focus on Functionality
  • 22.
    ★Styles – TDDvs BDD ★BDD = Behavior Driven Development Actually similar to TDD except: ★Focuses on Behavior and Specifications ★Specs (tests) are fluent and readable ★Readability makes them great for all levels of testing in the organization ★Hard to find TDD examples in JS that are not using BDD describe and it blocks
  • 23.
    ★TDD Example Test( ‘Emailaddress must not be blank’, function(){ notEqual(email, “”, "failed"); });
  • 24.
    ★BDD Example Describe( ‘EmailAddress’, function(){ It(‘should not be blank’, function(){ expect(email).not.toBe(“”); }); });
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
    ★Overview of TestingTools ★There are a few choices
  • 30.
  • 31.
    ★Jasmine ★Jasmine comes readyto go out of the box ★Fluent Syntax – BDD Style ★Includes lots of matchers ★Has spies included ★Very popular, lots of support ★Angular uses Jasmine with Karma (CLI) ★Headless running and plays well with CI servers
  • 32.
    ★Jasmine - Cons ★Asynctesting in 1.3 can be a headache ★Expects *spec.js suffix for test files ○This can be modified depending on how you are running the tests
  • 33.
    ★Jasmine – SampleTest describe("Hello world function", function() { it(”contains the word world", function() { expect(helloWorld()).toContain("world"); }); });
  • 34.
    ★Mocha★Simple Setup ★Simple Asynctesting ★Works great with other Assertion libraries like Chai ( not included ) ★Solid Support with CI Servers, with Plugins for others ★Opinion says Mocha blazing the trail for new features
  • 35.
    ★Mocha - Cons ★Requiresother Libraries for key features ○No Assertion Library included ○No Mocking / Spied included ○Need to create the runner manually ★Newer to the game so not as popular or supported as others but gaining traction.
  • 36.
    ★Mocha – BDDSample Test var expect = require('chai').expect; describe(’Hello World Function', function(){ it('should contain the word world', function(){ expect(helloWorld()).to.contain(’world'); }) })
  • 37.
    ★QUnit ★The oldest ofthe main testing frameworks ★Is popular due to use in jQuery and age ★Ember’s default Unit testing Framework
  • 38.
    ★QUnit - Cons ★Developmentslowed down since 2013 (but still under development) ★Syntax – No BDD style ★Assertion libraries – limited matchers
  • 39.
    ★QUnit – SampleTest QUnit.test( "ok test", function( assert ) { assert.ok( true, "true succeeds" ); assert.ok( "non-empty", "non-empty string succeeds" ); assert.ok( false, "false fails" ); assert.ok( 0, "0 fails" ); assert.ok( NaN, "NaN fails" ); assert.ok( "", "empty string fails" ); assert.ok( null, "null fails" ); assert.ok( undefined, "undefined fails" ); });
  • 40.
    ★Spaghetti Javascript Photo Credit– Kombination http://www.kombination.co.za/wp-content/uploads/2012/10/baby_w_spaghetti_mess_4987941.jpg
  • 41.
    ★Spaghetti Javascript Example Ifwe have time at the end
  • 42.
  • 43.
    ★Refactoring Spaghetti ★Things torefactor to make your code testable ○Code should not be one big chunk of Javascript in onReady() ○Deep nested callbacks & Anon functions cannot easily be singled out and tested ○Remove Tight Coupling – DOM access for example
  • 44.
    ★Object Literals var personObjLit= { ssn: ’xxxxxxxx', age: '35', name: 'Gavin Pickin', getAge: function(){ return this.age; }, getName: function() { return this.name; } };
  • 45.
    ★Module Pattern var personObjLit2= function() { ssn = ’xxxxxxx'; age = '35'; name = 'Gavin Pickin’; return { getAge: function(){ return age; }, getName: function() { return name; } }; };
  • 46.
    ★Using Testing inyour Workflow ★Using HTML Test Runners ○Keep a Browser open ○F5 refresh tests
  • 47.
    ★Command Line Tests ★RunJasmine – manual ○Run tests at the end of each section of work ★Run Grunt-Watch – automatic ○Runs Jasmine on every file change ○Grunt can run other tasks as well, minification etc
  • 48.
    ★Testing in yourIDE ★Browser Views ○Eclipse allows you to open files in web view – uses HTML Runner ★Run Jasmine / Grunt / Karma in IDE Console ○Easy to setup – See Demo– Sublime Text 2
  • 49.
    ★Live Demo and Examples *Install/ Run Jasmine Standalone for Browser *Install / Run Jasmine with NodeJs *Install/ Run Jasmine with Grunt Watch *Install / Run Grunt Watch inside Sublime Text 2
  • 50.
    ★Install / RunJasmine for In- Browser Testing Download standalone package from Github (I have 2.1.3) https://github.com/jasmine/jasmine/tree/master/dist Unzip into your /tests folder Run /tests/SpecRunner.html to see example tests
  • 51.
  • 52.
  • 53.
    ★SpecRunner Setup Jasmine BrowserTest <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Jasmine Spec Runner v2.1.3</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.1.3/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-2.1.3/jasmine.css”> <script src="lib/jasmine-2.1.3/jasmine.js"></script> <script src="lib/jasmine-2.1.3/jasmine-html.js"></script> <script src="lib/jasmine-2.1.3/boot.js"></script> <!-- include source files here... --> <script src="../js/services/loginService.js"></script> <!-- include spec files here... --> <script src="spec/loginServiceSpec.js"></script> </head> <body> </body> </html>
  • 54.
    ★Installing Jasmine with NodeJS Assumingyou have NodeJs Installed… install Jasmine $ npm install jasmine jasmine@2.2.1 node_modules/jasmine ├── exit@0.1.2 ├── jasmine-core@2.2.0 └── glob@3.2.11 (inherits@2.0.1, minimatch@0.3.0)
  • 55.
    ★Installing Jasmine with NodeJS OnceJasmine is installed in your project $ Jasmine init
  • 56.
    ★Installing Jasmine with NodeJS EditJasmine.json to update Locations for Spec Files and Helper Files { "spec_dir": "spec", "spec_files": [ "**/*[sS]pec.js" ], "helpers": [ "helpers/**/*.js" ] }
  • 57.
    ★Running Jasmine Tests withNodeJS$ Jasmine Started F Failures: 1) A suite contains spec with an expectation Message: Expected true to be false. Stack: Error: Expected true to be false. at Object.<anonymous> (/Users/gavinpickin/Dropbox/Apps/testApp/www/spec/test_spec.js:3: 18) 1 spec, 1 failure Finished in 0.009 seconds
  • 58.
    ★Running Jasmine Tests withNodeJS ★Jasmine-Node is great for Node ★Jasmine Node doesn’t have a headless browser ★Hard to test Browser code ★So what should I use?
  • 59.
    ★Installing Jasmine with GruntWatcher ★Install Grunt npm install grunt ★Install Grunt – Jasmine npm install grunt-contrib-jasmine ★Install Grunt – Watch npm install grunt-contrib-watch ★Note: On Mac, I also needed to install Grunt CLI npm install –g grunt-cli
  • 60.
    ★Configuring Jasmine with GruntWatcher // gruntfile.js - https://gist.github.com/gpickin/1e1e7902d1d3676d23c5 module.exports = function (grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('node_modules/grunt/package.json'), jasmine: { all: { src: ['js/*.js' ], options: { //'vendor': ['path/to/vendor/libs/*.js'], 'specs': ['specs/*.js' ] } } },
  • 61.
    ★Configuring Jasmine with GruntWatcher // gruntfile.js part 2 watch: { js: { files: [ 'js/*.js', 'specs/*.js', ], tasks: ['jasmine:all'] } } });
  • 62.
    ★Configuring Jasmine with GruntWatcher // gruntfile.js part 3 grunt.loadNpmTasks('grunt-contrib-jasmine'); grunt.loadNpmTasks('grunt-contrib-watch'); };
  • 63.
    ★Example Spec Jasminewith Grunt Watcher describe("A suite", function() { it("contains spec with an expectation", function() { expect(true).toBe(true); }); });
  • 64.
  • 65.
  • 66.
    ★Running in SublimeText 2 ★Install PackageControl into Sublime Text ★Install Grunt from PackageControl ○https://packagecontrol.io/packages/Grunt ★Update Grunt Sublime Settings for paths { "exec_args": { "path": "/bin:/usr/bin:/usr/local/bin” } } ★Then Command Shift P – grunt
  • 67.
  • 68.
    ★Refactoring Spaghetti ★Lets lookat some code ★This isn’t BEST PRACTICE, its BETTER PRACTICE than you were doing ★Its not really refactoring if you don’t have tests, its “moving code and asking for trouble”
  • 69.