【问题标题】:Mock service is not being injected but actual service is being injected未注入模拟服务,但正在注入实际服务
【发布时间】:2015-10-25 01:16:48
【问题描述】:

我正在尝试测试使用服务的控制器。当我在注入函数中运行以下测试和断点时,注入的是实际服务而不是模拟服务。为什么 $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());
    });

});

【问题讨论】:

    标签: javascript angularjs jasmine


    【解决方案1】:

    感谢@Yunchi。你指出了我的错误。

    您应该在模拟服务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.value 而不是使用$provide.factory。因为我们只需要确保contestantDataService 是一个对象并具有该功能。

    这里有一些类似的问题你可以检查,

    Injecting a mock into an AngularJS service.

    Mock a service in order to test a controller.

    Here is the jsfiddle I just created.

    玩得开心。 :)

    【讨论】:

      【解决方案2】:

      Tyler 的回答会奏效,但推理有点不对。

      module() 函数只是注册模块或模块初始化函数,inject() 函数稍后将使用这些函数来初始化 Angular 注入器。它绝不会将模拟服务与模块联系起来。

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-24
        • 1970-01-01
        • 2013-04-07
        • 1970-01-01
        • 1970-01-01
        • 2018-04-30
        • 1970-01-01
        • 2020-09-09
        相关资源
        最近更新 更多