Testing

Testing should always be a major part of any development project. Angular has been built from the beginning to be testable. It has clear separation of concerns; for example, you do not need to build a full DOM to test a controller. Angular also uses dependency injection everywhere, which makes mocking up objects very easy.

Unit testing with Jasmine and Karma

Jasmine and Karma are two tools that allow you to quickly and easily test your Angular code.

Jasmine

This is the actual unit testing library that we will use. Jasmine is a behavior-driven testing framework and is really easy to write.

Karma

Karma is the test runner that will watch your files and automatically kick off your tests. It runs on Node.js, so you must have it installed. You can then install Karma with npm:

 install karma-jasmine

Karma can watch your test files and rerun them whenever any of the files change. You can also debug tests in the browser if there are any issues. It is a great complement to Jasmine, and Google recommends both for testing.

ngMock

The ngMock handler is used to help mock up your application when testing. When testing, you will not want to create an entire DOM to load just one module. This is where ngMock can create a controller instance for use, and we can then test it.

Module

This allows you to load a module:

module(moduleName)

Parameters

  • The moduleName(string) function take

Description

You do not have a root element to put ng-app on, so module allows us to load a module to get access to its controllers, services, and directives. You should only use this function in tests after loading ngMock.

Inject

This gets the Angular inject services:

inject(toBeInjected)

Parameters

  • The toBeInjected(function) function works much like other injected functions. List out the objects to be injected, and they will be available in the function body.

Description

Use inject to get access to built-in Angular services, such as $controller and $compile, or use it to get access to a loading module's services.

Inject can load dependencies if they are wrapped with underscores. For example, inject would load $compile if it is used as _$compile_. This is done because in a test, we will need to create a reference to the $compile service, and most likely, we would want to use $compile as the variable name. The underscores allow you to inject it and use the $compile variable.

$httpBackend

This can create a mock response:

$httpBackend.when(requestType, url, [requestParameters], [headers])
$httpBackend.expect(requestType, url, [requestParameters], [headers])
$httpBackend.respond(response)

Parameters

  • requestType(string): This is the HTTP method of the request
  • url(string): This is the URL of the request
  • requestParameters(object): These are the parameters of the request
  • headers(object): These are the headers for the request
  • response(string, object): This is the response of the request

Return value

This returns a handler that can call respond.

Description

Making AJAX calls is a perfect example of something that should not be done in a unit test. There are too many things out of your control for unit testing. The $httpBackend handler is provided by ngMock so that you can create a mock response.

The handler must match the expected method and URL at the very least. You can also match the optional parameters and headers if you plan on making specific requests with them.

When the request is matched, you can send back a string or object as the response. This allows you to create a test that uses $httpBackend, as you know what the response is going to be.

The difference between expect and when is that expect has to be called in the test, whereas when does not have that requirement.

Unit testing controllers

Here is an example of a simple unit test for a controller. First, you must create a controller and then load it in our test:

var firstModule = angular.module('firstModule', ['ngMock']);
firstModule.controller('SimpleController', ['$scope', function ($scope) {
  $scope.test = 'HEY!';
}]);

You can now create the test. In the test, you must load the firstModule module, inject $controller, and create an instance of SimpleController. Here is the test:

describe('SimpleController', function () {
  var scope = {};
  var simpleCtrl;
  beforeEach(module('firstModule'));

  it("should have a scope variable of test", inject(function ($controller) {
    expect(scope.test).toBe(undefined);
    simpleCtrl = $controller('SimpleController', { $scope: scope });
    expect(scope.test).toBe('HEY!');
  }));
});

Unit testing directives

This example will show you how to test a directive. First, create the directive:

firstModule.directive('simpleDirective', function () {
  return {
    restrict: 'E',
    scope:{
      test: '@'
    },
    replace: true,
    template: '<div>This is an example {{test}}.</div>'
  };
});

Next, you will need to load the module, inject $compiler and $rootscope, compile the directive, and finally, start the digest loop at least once to bind any values:

describe('simpleDirective', function () {
  var $compile, $rootScope;
  beforeEach(module('firstModule'));
  beforeEach(inject(function (_$compile_, _$rootScope_) {
    $compile = _$compile_;
    $rootScope = _$rootScope_;
  }));

  it('should have our compiled text', function () {
    var element = $compile('<simple-directive test="directive"></simple-directive>')($rootScope);
    $rootScope.$digest();
    expect(element.html()).toContain('This is an example directive.');
  });

});

Unit testing services

The final testing example will test a service. First, create a service:

firstModule.factory('firstFactory', ['$http', function ($http) {
  return {
    addOne: function () {
      return $http.get('/test', {})
      .then(function (res) {
        return res.data.value + 1;
      });
    }
  }
}]);

Next, you will have to load the module, inject $httpBackend and the service factory, create a response, and load the response. Notice the use of $httpBackend.flush(). This will send the response to any open requests:

describe('firstFactory', function () {
  var $httpBackend, testingFactory, handler;

  beforeEach(module('firstModule'));
  beforeEach(inject(function (_$httpBackend_, firstFactory) {
    $httpBackend = _$httpBackend_;
    handler = $httpBackend.expect('GET', '/test')
    .respond({ value: 1 });
    testingFactory = firstFactory;
  }));

  it('should run the GET request and add one', function () {
    testingFactory.addOne()
    .then(function (data) {
      expect(data).toBe(2);
    });
    $httpBackend.flush();

  });
});
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.134.17