Testing AngularJS

Post on 11-May-2015

765 views 2 download

Tags:

description

A walkthrough inside testing core concepts and how to apply them with AngularJS, plus an overview on the tools.

transcript

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?