Mocking HTTP service unit test with AngularJS and Jasmine

拜拜、爱过 提交于 2020-01-07 07:36:11

问题


I am attempting to build a mock service so that my unit tests can verify certain functions are called and updated accordingly. Unfortunately I cannot get this to work.

Im currently getting an error undefined is not a function on this line:

spyOn(statusService, 'getModuleStatus').andCallThrough();

My actual service looks like this:

serviceStatusServices.factory('serviceStatusAppAPIservice', function ($http) {

    var serviceStatusAppAPI = {};

    serviceStatusAppAPI.getModuleStatus = function () {
        return $http({
            method: 'JSON',
            url: '/settings/getservicestatusandconfiguration'
        });
    }

    serviceStatusAppAPI.setModuleStatus = function (module) {
        return $http({
            method: 'POST',
            url: '/settings/setservicestatusandconfiguration',
            data: { moduleId: module.ModuleId, configData: module.ConfigValues }
        });
    }

    return serviceStatusAppAPI;
});

My update function

serviceStatusControllers.controller('serviceStatusController', ['$scope', 'serviceStatusAppAPIservice', '$filter', '$timeout', function ($scope, serviceStatusAppAPIservice, $filter, $timeout) {

    $scope.update = function () {
        $scope.loading = true;
        serviceStatusAppAPIservice.getModuleStatus().then(function (response) {

            $scope.modules = $filter('orderBy')(response.data.moduleData, 'ModuleName')
            ...

My tests look like this

describe('ServiceStatusController', function () {
    beforeEach(module("serviceStatusApp"));

    var scope;
    var statusService;
    var controller;
    var q;
    var deferred;

    // define the mock people service
    beforeEach(function () {
        statusService = {
            getModuleStatus: function () {
                deferred = q.defer();
                return deferred.promise;
            }
        };
    });

    // inject the required services and instantiate the controller
    beforeEach(inject(function ($rootScope, $controller, $q) {
        scope = $rootScope.$new();
        q = $q;
        controller = $controller('serviceStatusController', { 
                     $scope: scope, serviceStatusAppAPIservice: statusService });
    }));

    describe("$scope.update", function () {
        it("Updates screen", function () {
            spyOn(statusService, 'getModuleStatus').andCallThrough();

            scope.update();

            deferred.resolve();

            expect(statusService.getModuleStatus).toHaveBeenCalled();
            expect(scope.modules).not.toBe([]);
        });
    });
});

Also, how do I pass any mock data returned from the service to the caller. Currently in my model I do serviceStatusAppAPI.getModuleStatus(data) then use data.Data to get out the returned JSON.


回答1:


I assume if you are doing something like this in your ctrl

scope.update = function() {
    serviceStatusAppAPIservice.setModuleStatus(url).then(function (data) {
        scope.modules = data;
    })    
};

Service which returns promise

.factory('serviceStatusAppAPI', function($http, $q) {
        return {
            getModuleStatus: function() {
                var defer = $q.defer();
                $http({method: 'GET', url: '/settings/getservicestatusandconfiguration'})
                    .success(function(data, status, headers, config) {
                        // this callback will be called asynchronously
                        // when the response is available
                        defer.resolve(data);
                    })
                    .error(function(data, status, headers, config) {
                        // called asynchronously if an error occurs
                        // or server returns response with an error status.
                        window.data = data;
                    });

                return defer.promise;
            }
        };
    });

So in you controller you will get data like this

serviceStatusAppAPI.getModuleStatus().then(function (data) {
    $scope.modules = $filter('orderBy')(data.moduleData, 'ModuleName')
})

This is how you can run your unit test case

beforeEach(function() {

    var statusService = {};

    module('myApp', function($provide) {
        $provide.value('serviceStatusAppAPIservice', statusService);
    });

    statusService.modalStatus = {
        moduleData: [{ModuleName: 'abc'}, {ModuleName: 'def'}]
    };

    inject(function ($q) {
        statusService.setModuleStatus = function () {
            var defer = $q.defer();

            defer.resolve(this.modalStatus);

            return defer.promise;
        };

        statusService.getModuleStatus = function () {
            var defer = $q.defer();

            defer.resolve(this.modalStatus);

            return defer.promise;
        };

    });
});

beforeEach(inject(function ($rootScope, $controller, _$stateParams_) {
    scope = $rootScope.$new();
    stateParams = _$stateParams_;
    controller = $controller;
}));

var myCtrl = function() {
    return controller('ServiceStatusController', {
                $scope: scope,
            });
};

it('should load status', function () {
    myCtrl();
    scope.update();
    scope.$digest();
    expect(scope.modules).toBe({
        status: 'active'
    });
});


来源:https://stackoverflow.com/questions/27174673/mocking-http-service-unit-test-with-angularjs-and-jasmine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!