* who am i? * state of the room? * ways to test javascript? * different testing environments? *...

58
* How do I write Testable Javascript?

Upload: bertha-boone

Post on 21-Dec-2015

219 views

Category:

Documents


0 download

TRANSCRIPT

*How do I writeTestable

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

*What else do you need to know?

*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.

*Ways to Test Javascript

*Click around in the browser yourself

*Setup Selenium / Web Driver to click around for you

*Structured Programmatic Tests

*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

*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 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 DevelopmentActually 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 TestQUnit.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

*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

*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”

*Object Literals

var personObjLit = {

ssn: '123456789',

age: '35',

name: 'Gavin Pickin',

getAge: function(){

return this.age;

},

getName: function() {

return this.name;

}

};

*Module Pattern

var personObjLit2 = function() {

ssn = '123456789';

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 TestingDownload 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

[email protected] node_modules/jasmine

├── [email protected]

├── [email protected]

└── [email protected] ([email protected], [email protected])

*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 Gruntnpm install grunt

*Install Grunt – Jasminenpm install grunt-contrib-jasmine

*Install Grunt – Watchnpm install grunt-contrib-watch

*Note: On Mac, I also needed to install Grunt CLInpm 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

*Q&A

*Any questions?

*Come check out my Cordova Hooks session and see how you can run Unit Tests (and much more) whenever you’re preparing a build for your cordova app.