模拟服务没有注入,但正在注入实际服务

时间:2015-08-03 02:40:53

标签: javascript angularjs jasmine

我正在尝试测试使用服务的控制器。当我在inject函数中运行以下测试和断点时,将注入实际服务而不是模拟服务。为什么通过$ provider.factory定义的服务没有被注入?

"use strict";

describe("contestantController", function () {
    var dataService, rootScope, scope, passPromise, contestantController;

    beforeEach(function(){
        module(function ($provide) {

            //mock service
            $provide.factory('contestantDataService', ['$q', function ($q) {
                function save(data){
                    if(passPromise){
                        return $q.when();
                    } else {
                        return $q.reject();
                    }
                }
                function getData() {
                    if (passPromise) {
                        return $q.when(smallDataSet());
                    } else {
                        return $q.reject();
                    }
                }
                return {
                    addContestant: save,
                    getContestants: getData,
                };
            }]);

        });

        module('contestantApp');
    });

    beforeEach(inject(function ($rootScope, $controller, contestantDataService) {
        rootScope = $rootScope;
        scope = $rootScope.$new();
        dataService = contestantDataService;

        spyOn(dataService, 'getContestants').and.callThrough();

        contestantController = $controller('contestantController', {
            $scope: scope,
            contestantDataService: dataService
        });
    }));

    it('should call getContestants method on contestantDataService on calling saveData', function () {

        passPromise = true;
        rootScope.$digest();

        expect(dataService.getContestants).toHaveBeenCalled();
        expect(scope.contestants).toEqual(smallDataSet());
    });

});

2 个答案:

答案 0 :(得分:3)

泰勒的回答是有效的,但推理有点过时了。

module()函数只是注册inject()函数稍后用于初始化Angular注入器的模块或模块初始化函数。它绝不会将模拟服务与模块链接起来。

您的代码不起作用,因为服务注册的顺序很重要。您的代码首先注册一个模拟contestantDataService,然后注册contestantApp模块,该模块包含自己的contestantDataService,覆盖已注册的模拟。如果您只是将module('contestantApp')调用移到顶部,它应该按预期工作。

所以这意味着下面的两个方块是等效的,并且都可以工作......

beforeEach(function(){
  module('contestantApp');
  module(function ($provide) {
    ...
  });
);

beforeEach(function(){
  module('contestantApp', function ($provide) {
    ...
  });
);

答案 1 :(得分:2)

@Yunchi的Thx。你指出了我的错误。

在模拟服务contestantDataService之前,您应该调用模块函数。

只需以这种方式更新您的代码,

//make sure contesttantDataService exist in this module in your production environment.

var dataService, rootScope, scope, passPromise, contestantController;
beforeEach(function(){
    //Add module name here which means we define the mockService under this module
    module('contestantApp', function ($provide) {
        //mock service
        $provide.factory('contestantDataService', ['$q', function ($q) {
            function save(data){
                if(passPromise){
                    return $q.when();
                } else {
                    return $q.reject();
                }
            }
            function getData() {
                if (passPromise) {
                    return $q.when(smallDataSet());
                } else {
                    return $q.reject();
                }
            }
            return {
                addContestant: save,
                getContestants: getData,
            };
        }]);
    });
    beforeEach(inject(function ($rootScope, $controller, contestantDataService) {
         rootScope = $rootScope;
         scope = $rootScope.$new();
         dataService = contestantDataService;

         spyOn(dataService, 'getContestants').and.callThrough();
         //no need to manually inject to our controller now.
         contestantController = $controller('contestantController', {
             $scope: scope
     });
}));

我认为最好在我们的单元测试中使用$provide.factory,而不是使用$provide.value。因为我们只需要确保contestantDataService是一个对象并具有该功能。

以下是您可以查看的类似问题,

Injecting a mock into an AngularJS service.

Mock a service in order to test a controller.

Here is the jsfiddle I just created.

玩得开心。 :)