* who am i? * state of the room? * ways to test javascript? * different testing environments? *...
TRANSCRIPT
*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.
*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();
*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
*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;
}
};
};
*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
*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])
*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 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