angularjs - Unit testing angular.js service (node.js server) in controller -
i'm new unit testing in client side. application uses express.js, angularjs-ui-router , node.js. start writing unit test cases application. i'm using karma, mocha, chai, sinon unit testing.
my router config below:
$stateprovider .state('drive', { url: '/drive', templateurl: 'drive.jade', controller: 'drivectrl', });
controller:
angular.module('mapp').controller('drivectrl', ['$scope', 'driveservice', function($scope, driveservice) { var driveinfo = driveservice.get({}, function() {}); driveinfo.$promise.then(function(rs) { var drivers = []; //logical operation $scope.drivers = drivers; }); }]);
factory resource:
mapp.factory('driveservice', ['$resource', function($resource) { return $resource('/drive/id/:id/', {id:'@id'}); }]);
the driveservice factory insides uses angular.js $resources. tried variety of options nothings seems working (using $httpbackend, $q). can me out write way test controller mocking driveservice.
here's unit test code:
var expect = require('chai').expect; var sinon = require('sinon'); describe('drive service initialisation', function() { var scope, controller, state, $q, mockdriveservice, driveserviceresponse = [{name:'james', type: 'heavy'}], querydeferred; beforeeach(angular.mock.module('mapp')); angular.mock.module(function($provide){ $provide.value('driveservice', mockdriveservice); }); describe(' drive service called', function() { beforeeach(inject(function($controller, $rootscope, $state, _$q_, driveservice) { $q = _$q_; scope = $rootscope.$new(); mockdriveservice = { get:function(){ querydeferred = $q.defer(); querydeferred.resolve(driveserviceresponse); return {$promise: querydeferred.promise}; } }; controller = $controller('drivectrl', { $scope: scope, driveservice:driveservice}); sinon.stub(mockdriveservice, 'get'); scope.$apply(); })); it('expect filter empty', function () { expect(scope.drivers).to.not.be.empty; }); }); });
the error i'm getting is:
error: unexpected request: /driveservice/id no more request expected @ $httpbackend (node_modules/angular-mocks/angular-mocks.js:1210:9) @ sendreq (public/javascripts/lib/angular/angular.js:10333:9) @ serverrequest (public/javascripts/lib/angular/angular.js:10045:16) @ processqueue (public/javascripts/lib/angular/angular.js:14567:28) @ public/javascripts/lib/angular/angular.js:14583:27 @ scope.$eval (public/javascripts/lib/angular/angular.js:15846:28) @ scope.$digest (public/javascripts/lib/angular/angular.js:15657:31) @ scope.$apply (public/javascripts/lib/angular/angular.js:15951:24) @ context.<anonymous> (c:/users/por/appdata/local/temp/b0475694b46e0d60262621ad126ce46c.browserify:63:9) @ object.invoke (public/javascripts/lib/angular/angular.js:4450:17) error: declaration location @ window.inject.angular.mock.inject (node_modules/angular-mocks/angular-mocks.js:2375:25)
you're defining mocked service still providing unmocked driveservice
controller (this has been done default).
the fact driveservice.get
stubbed after controller instantiated , method called, doesn't case.
it should like
mockdriveservice = { get: sinon.stub().returns({$promise: $q.resolve(driveserviceresponse)}) }; controller = $controller('drivectrl', { $scope: scope, driveservice:mockdriveservice}); scope.$apply();
the app should have test-friendly design tested efficiently. considering router loaded in top-level module , configuration defined there too, app units supposed tested should defined in child modules, tested in isolation.
the app may refactored as
angular.module('mapp', ['ui.router', 'mapp.drive']); ... angular.module('mapp.drive', []) .controller('drivectrl', ...) .factory('driveservice', ...);
and units may tested like
beforeeach(angular.mock.module('mapp.drive')); ...
Comments
Post a Comment