Upload
jacopo-nardiello
View
770
Download
2
Tags:
Embed Size (px)
DESCRIPTION
A walkthrough inside testing core concepts and how to apply them with AngularJS, plus an overview on the tools.
Citation preview
Testing!AngularJS
Jacopo NardielloPadawan Programmer
Presentation code on Github: github.com/jnardiello/angularjsday-testing-angular
Why?
Fail in Production
Fail in dev
Thanks to testing we…
fail fast
No Debugging
Machines handles bug hunting
Tests are a tool to handle complexity
Angular is no exception
Rock solid code
Benefits
Fast Dev Cycle
Benefits
Rock solid code
Relaxed Team
Benefits
Fast Dev Cycle
Rock solid code
Relaxed Team
Benefits
Fast Dev Cycle
Rock solid code
Relaxed PM
Testing Javascript
Testing Javascript
describe(“…”, function() { it(“should do something", function() { expect(true).toBe(true); }); });
Testing Javascript
describe(“…”, function() { it(“should do something", function() { expect(true).toBe(true); }); });
Types of tests
Unit tests
• Small portions of code
• Code is isolated
• Quick and easy
Integration tests
Interaction between elements
• From the product owner point of view
• They are (computationally) expensive and slow
Acceptance tests
Angular is special
Misko Hevery
“Agile Coach at Google where he is responsible for coaching Googlers to maintain the high level of automated testing culture”
- misko.hevery.com/about/
Misko Hevery
+
“Angular is written with testability in mind”
- Angular Doc
Why is Angular easily testable?
Dependency Injection
DI
As a Pattern Framework
DI as Patternfunction Car() { var wheel = new Wheel(); var engine = Engine.getInstance(); var door = app.get(‘Door’); ! this.move = function() { engine.on(); wheel.rotate(); door.open(); } }
DI as Patternfunction Car() { var wheel = new Wheel(); var engine = Engine.getInstance(); var door = app.get(‘Door’); ! this.move = function() { engine.on(); wheel.rotate(); door.open(); } }
DI as Pattern
function Car(wheel, engine, door) { this.move = function() { engine.on(); wheel.rotate(); door.open(); } }
The problemfunction main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
The problemfunction main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
The problemfunction main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
The problemfunction main() { var fuel = new Fuel(); var electricity = new Electricity(); var engine = new Engine(fuel); var door = new Door(Electricity); var wheel = new Wheel(); var car = new Car(wheel, engine, door); car.move(); }
DI as frameworkfunction main() { var injector = new Injector(….); var car = injector.get(Car); car.move(); }
DI as frameworkfunction main() { var injector = new Injector(….); var car = injector.get(Car); car.move(); }
Car.$inject = [‘wheel’, ‘engine’, ‘door’]; function Car(wheel, engine, door) { this.move = function() { … } }
DI as frameworkfunction main() { var injector = new Injector(….); var car = injector.get(Car); car.move(); }
Car.$inject = [‘wheel’, ‘engine’, ‘door’]; function Car(wheel, engine, door) { this.move = function() { … } }
Angular testability is super-heroic!
but…
“you still have to do the right thing.”- Angular Doc
Testability
1. Don’t use new2. Don’t use globals
The Angular Way
Solid structured code
Testing components
Controllerfunction RocketCtrl($scope) { $scope.maxFuel = 100; $scope.finalCheck = function() { if ($scope.currentFuel < $scope.maxFuel) { $scope.check = ‘ko’; } else { $scope.check = 'ok'; } }; }
Controllerfunction RocketCtrl($scope) { $scope.maxFuel = 100; $scope.finalCheck = function() { if ($scope.currentFuel < $scope.maxFuel) { $scope.check = ‘ko’; } else { $scope.check = 'ok'; } }; }
var $scope = {}; var rc = $controller( 'RocketCtrl', { $scope: $scope } ); !$scope.currentFuel = 80; $scope.finalCheck(); expect($scope.check).toEqual('ko');
Controller Test
Directiveapp.directive('rocketLaunchPad', function () { return { restrict: 'AE', replace: true, template: ‘<rocket-launch-pad> Rocket here <rocket-launch-pad>’ }; });
Directive Test
it(‘Check launchpad was installed', function() { var element = $compile(“<rocket-launch-pad></rocket-launch-pad>”)($rootScope); ! expect(element.html()).toContain("Rocket here"); });
Filter Test.filter('i18n', function() { return function (str) { return translations.hasOwnProperty(str) && translations[str] || str; } })
var length = $filter('i18n'); expect(i18n(‘ciao’)).toEqual(‘hi’); expect(length(‘abc’)).toEqual(‘abc');
Tools
Karma
Protractor
Test Runner
Karma
Run tests against real browsers
Karma
Run tests against real browsers
Unit tests
Config file> karma init
Config file> karma init
- frameworks: [‘jasmine’]
Config file> karma init
- frameworks: [‘jasmine’]- autoWatch: true
Config file> karma init
- frameworks: [‘jasmine’]
- files: [ ‘../tests/controllerSpec.js’ ],
- autoWatch: true
Config file> karma init
- frameworks: [‘jasmine’]
- files: [ ‘../tests/controllerSpec.js’ ],
- autoWatch: true
- browsers: ['Chrome']
Using Karma> karma start config.js
Using Karma> karma start config.js
• From the product owner point of view
• They are (computationally) expensive and slow
Acceptance tests
• They can be very slow
• Hard to write
• Hard to keep updated
Acceptance tests
ProtractorE2E Angular Testing
Angular wrapper for WebDriver
Anatomy of a E2E testdescribe(‘…’, function() { it(‘…’, function() { browser.get(‘…’); element(by.model(‘…’)).sendKeys(..); ! var calculate = element(by.binding(‘…’)); ! expect(some.method()).toEqual(..); }); });
Global Variablesdescribe(‘…’, function() { it(‘…’, function() { browser.get(‘…’); element(by.model(‘…’)).sendKeys(..); ! var calculate = element(by.binding(‘…’)); ! expect(some.method()).toEqual(..); }); });
Global Variablesdescribe(‘…’, function() { it(‘…’, function() { browser.get(‘…’); element(by.model(‘…’)).sendKeys(..); ! var calculate = element(by.binding(‘…’)); ! expect(some.method()).toEqual(..); }); });
Super-Happy Panda!
Page Objects
Protractor provides
Page Objects
Protractor provides
Debugging with superpowers
Page Objects
Protractor provides
Debugging with superpowersAngular-specific functions
Get your hands dirty!https://github.com/jnardiello/angularjsday-testing-angular
Tools in action - http://vimeo.com/86816782
Jacopo NardielloTwitter: @jnardiello
Say hi!
Jacopo NardielloTwitter: @jnardiello
Questions?