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.
2. nirkaufman@gmail.com
Download the reference project at:
https://github.com/nirkaufman/angularjs-unit-testing-demo
contact me at: nirkaufman@gmail.com
or
http://www.linkedin.com/in/nirkaufman
4. nirkaufman@gmail.com
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.
6. nirkaufman@gmail.com
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.
8. nirkaufman@gmail.com
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/
9. nirkaufman@gmail.com
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/
11. nirkaufman@gmail.com
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
12. nirkaufman@gmail.com
$ 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)
13. nirkaufman@gmail.com
$ 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
14. nirkaufman@gmail.com
$ 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
16. nirkaufman@gmail.com
$ 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
18. nirkaufman@gmail.com
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
19. nirkaufman@gmail.com
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
20. nirkaufman@gmail.com
// spy on the method setBar of foo object
spyOn(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
22. nirkaufman@gmail.com
$ 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
24. nirkaufman@gmail.com
// get the module that contain the controller
beforeEach(module('todolist'));
// inject the $controller and the rootScope
beforeEach(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.
26. nirkaufman@gmail.com
// get the module that contain the service
beforeEach(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
28. nirkaufman@gmail.com
// get the module that contain the service
beforeEach(module('todolist'));
// inject the $compile service and the $rootScope
beforeEach(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.
30. nirkaufman@gmail.com
// inject the $httpBackend service and the $rootScope
beforeEach(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
32. nirkaufman@gmail.com
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 usite
ddescribe()
// run this spec
iit()
// run this spec
xit()
webstorm users can install the ddescriber for jasmine
33. nirkaufman@gmail.com
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
34. nirkaufman@gmail.com
Thank You!
Download the reference project at:
https://github.com/nirkaufman/angularjs-unit-testing-demo
contact me at: nirkaufman@gmail.com
or
http://www.linkedin.com/in/nirkaufman