34
Unit Testing in Practice

Angularjs - Unit testing introduction

Embed Size (px)

DESCRIPTION

A presentation made for the AngularJS-IL meetup group that took place in May 2014 at Google TLV Campus. its a demonstration of Unit testing an AngularJS component with jasmine and karma.

Citation preview

Page 1: Angularjs - Unit testing introduction

Unit Testing in Practice

Page 2: Angularjs - Unit testing introduction

[email protected]

Download the reference project at:

https://github.com/nirkaufman/angularjs-unit-testing-demo

contact me at: [email protected]

http://www.linkedin.com/in/nirkaufman

Page 3: Angularjs - Unit testing introduction

[email protected]

Getting Started with Unit Testing

Intruduction

Page 4: Angularjs - Unit testing introduction

[email protected]

About Unit Testing

The primary goal of unit testing is to take the smallest piece of testable

software in the application, isolate it from the remainder of the code, and

determine whether it behaves exactly as you expect.

Page 5: Angularjs - Unit testing introduction

[email protected]

Testing AngularJS App`s

AngularJS build around the concept of dependency injection & loose coupling

to the DOM which make it a very tesable.

Page 6: Angularjs - Unit testing introduction

[email protected]

Test Driven Developemnt

a software development process that relies on the repetition of a very short

development cycle: first the developer writes an (initially failing) automated

test case that defines a desired improvement or new function, then produces

the minimum amount of code to pass that test, and finally refactors the new

code to acceptable standards.

Page 7: Angularjs - Unit testing introduction

[email protected]

RED(fail)

Green(pass)

REFACTOR

1. write a test that fails

2. write only enougth code to make it pass

3. improve code quality

Test Driven Developemnt

Page 8: Angularjs - Unit testing introduction

[email protected]

The main goal for Karma is to bring a productive testing environment to developers. The environment being one where they don't have to set up

loads of configurations, but rather a place where developers can just write the code and get instant feedback from their tests. Because getting quick

feedback is what makes you productive and creative.

http://karma-runner.github.io/

Page 9: Angularjs - Unit testing introduction

[email protected]

Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript

frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.

http://jasmine.github.io/

Page 10: Angularjs - Unit testing introduction

[email protected]

Setting up our TDD Enveirment

Project Setup

Page 11: Angularjs - Unit testing introduction

[email protected]

Let`s start from scratch.First, we need to create a basic project structure with a

folder that contain our sources, and a folder that contains our specs. then we can init a package.json

$ npm init

Page 12: Angularjs - Unit testing introduction

[email protected]

$ npm install karma

let`s install Karma (and all the plugins your project needs) locally in the project's directory.(don`t forget to use the --save-dev flags)

Page 13: Angularjs - Unit testing introduction

[email protected]

$ npm install karma-jasmine

$ npm install karma-chrome-launcher

since we going to use jasmine, let`s install tha karma adaptor plugin for jasmine.

we will also install the chrome launcher plugin to enable karma to launch chrome browser fo us

Page 14: Angularjs - Unit testing introduction

[email protected]

$ npm install -g karma-cli

Finally, we will install the karma command line interface (cli) globally, which enable us to easily configure karma

in our project

Page 15: Angularjs - Unit testing introduction

[email protected]

$ karma init

with the karma cli installed, we can create our configuration file fast and easy.

Page 16: Angularjs - Unit testing introduction

[email protected]

$ karma start

$ karma run

Let`s take karma for a test drive:in webstorm, right click on the configuration file and

choose run.if you don`t use webstorm, start the karma server with

start, and run you tests with run

Page 17: Angularjs - Unit testing introduction

[email protected]

quick intruduction to the Jasmine framwork

Jasmine 101

Page 18: Angularjs - Unit testing introduction

[email protected]

describe("suite name", function() {

it("contains spec with an expectation", function() { expect(true).toBe(true); });

});

in jasmine, we begin by creating a test suite with the global describe function that wrap our specs.

specs are defined by the global function it.inside the spec we can describe our expextations by

using tha expect function chained to a matcher function

Page 19: Angularjs - Unit testing introduction

[email protected]

describe("suite name", function() { beforeEach(function () {//excute before each spec})

it("contains spec with an expectation", function() { expect(true).toBe(true); });

afterEach(function () {//excute after each spec})

});

we can run code before and after each spec in a suite block using the beforeEach and afterEach functions

Page 20: Angularjs - Unit testing introduction

[email protected]

// spy on the method setBar of foo objectspyOn(foo, 'setBar');

it("contains spec with an expectation", function() { expect(foo.setBar).toHaveBeenCalled();

expect(foo.setBar).toHaveBeenCalledWith(32); });});

jasmine use spies to track calls to a function with all it`s arguments.

There are special matchers for interacting with spies. The toHaveBeenCalled and The

toHaveBeenCalledWith

Page 21: Angularjs - Unit testing introduction

[email protected]

Test Driven Development in practice

Testing AngularJS

Page 22: Angularjs - Unit testing introduction

[email protected]

$ bower install angular

$ bower install angular-mocks

We are going to develop a small Task Manger app.in the process we will learn how to unit test the building

blocks of every AngularJS application:controllers, services, directives, events & http requests.

First, let`s get some resources using bower

Page 23: Angularjs - Unit testing introduction

[email protected]

Controllers

Page 24: Angularjs - Unit testing introduction

[email protected]

// get the module that contain the controllerbeforeEach(module('todolist'));

// inject the $controller and the rootScopebeforeEach(inject(function ($rootScope, $controller) { // create a fresh new scope for the controller

scope = $rootScope.$new(); // create a controller with this scope

ctrl = $controller('TodoListController',{$scope: scope});}));

In order to test controllers we need to holds an instance of the controller, initialize a scope for it and testing our

expectations against that scope.

Page 25: Angularjs - Unit testing introduction

[email protected]

services

Services

Page 26: Angularjs - Unit testing introduction

[email protected]

// get the module that contain the servicebeforeEach(module('todolist'));

// inject the $injector beforeEach(inject(function ($injector) { // use the $injector to get a hold on the service

service = $injector.get(‘ServiceName’);}));

In order to test services we need to use the $injector to get an instance of the service

Page 27: Angularjs - Unit testing introduction

[email protected]

Directive

Page 28: Angularjs - Unit testing introduction

[email protected]

// get the module that contain the servicebeforeEach(module('todolist'));

// inject the $compile service and the $rootScopebeforeEach(inject(function ($compile, $rootScope) { // use the $rootScope to create a scope for the directive

scope = $rootScope; // create an angular element from a HTML string element = angular.element(‘<div my-directive ></div>’)// compile the element with the scope$compile(element)(scope)scope.$apply()

}));

In order to test a directive, we need to create an element that will host the directive and compile it with a

scope. in our spec, we need trigger the digest.

Page 29: Angularjs - Unit testing introduction

[email protected]

http requests

Page 30: Angularjs - Unit testing introduction

[email protected]

// inject the $httpBackend service and the $rootScopebeforeEach(inject(function ($httpBackend) { // use the $rootScope to create a scope for the directive

httpBackend = $httpBackend;

it("somting that make a request", function() {// expect a request

httpBackend.expectGET(‘\api’).respond(200);// code that make a request

httpBackend.flush(); // do`nt forget to flush.. });

}));

the $httpBackend is a fake HTTP Back-end implementaion. in the most basic use we can verify that

a request is made & stub responses

Page 31: Angularjs - Unit testing introduction

[email protected]

Productive TipsMaking testing even more easier

Page 32: Angularjs - Unit testing introduction

[email protected]

When the number of test suites and specs grows larger, the overall test speed is affected.

jasmine include some usfull syntax to control it.

// run this usiteddescribe()

// run this speciit()

// run this specxit()

webstorm users can install the ddescriber for jasmine

Page 33: Angularjs - Unit testing introduction

[email protected]

in webstorm the run panel enable us some more featuers like:

Set Auto Test Delay Time

Export Test Results

Filter and sort

Run / Debug Configuration

live templates

Page 34: Angularjs - Unit testing introduction

[email protected]

Thank You!

Download the reference project at:

https://github.com/nirkaufman/angularjs-unit-testing-demo

contact me at: [email protected]

http://www.linkedin.com/in/nirkaufman