Upload
nir-kaufman
View
3.309
Download
0
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
Unit Testing in Practice
Download the reference project at:
https://github.com/nirkaufman/angularjs-unit-testing-demo
contact me at: [email protected]
http://www.linkedin.com/in/nirkaufman
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.
Testing AngularJS App`s
AngularJS build around the concept of dependency injection & loose coupling
to the DOM which make it a very tesable.
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.
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
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/
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/
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
$ 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)
$ 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
$ 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
$ karma init
with the karma cli installed, we can create our configuration file fast and easy.
$ 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
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
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
// 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
$ 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
Controllers
// 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.
// 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
Directive
// 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.
http requests
// 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
Productive TipsMaking testing even more easier
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
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
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