简体   繁体   English

如何使用Jasmine / Karma模拟AngularJS Promise?

[英]How to mock AngularJS promises using Jasmine / Karma?

This is my controller: 这是我的控制器:

angular.module("AuthenticationApp", ["BaseApp"])
    .controller("AuthCtrl", ["$http", "BaseService", function($http, BaseService) {
        var self = this;

        BaseService.fetch.stuffs()
          .then(function(data) {
            self.stuffs = data;
        });

    }]);

This my BaseService (the factory I need to mock): 这是我的BaseService (我需要模拟的工厂):

angular.module("BaseApp", ["ngRoute"])

    .factory("BaseService", ["$http", "$q", function($http, $q) {
        var self = this;

        self.fetch = {
         stuffs: function() {
           return $http.get("/api/stuffs/")
             .then(function(response) {
                 return response.data;
           });
         }
        };    

        return self;
    }]);

I have no idea where to start. 我不知道从哪里开始。 What I tried was this: 我试过的是:

describe('Controller: AuthCtrl', function() {
    var ctrl, mockBaseService;

    beforeEach(function() {

        mockBaseService = {
            stuffs: 'test',
            fetch: { 
                stuffs: function() {
                    return {
                      then: function() {
                          return {stuffs: "stuffs"};
                      },
                    }
                },
            },
        };

        spyOn(mockBaseService.fetch, 'stuffs');

        module('BaseApp', function($provide) {
            $provide.value('BaseService', mockBaseService);
        });

        module('AuthenticationApp');

        inject(function($controller) {
            ctrl = $controller('AuthCtrl', {
            });
        });
    });

    it('BaseService.fetch.stuffs should be called on page load', function() {
        expect(mockBaseService.fetch.stuffs).toHaveBeenCalled();
        expect(ctrl.stuffs).toBe({stuffs: "stuffs"});
    });

});

But when I test this code, I get an error saying: 但是,当我测试此代码时,出现错误消息:

TypeError: Cannot read property 'then' of undefined
    at new <anonymous> (/home/user/Documents/ebdjango/ebdjangoapp/static/js/home.js:15:11)

home.js line 15 is this line in the controller: home.js第15行是控制器中的以下行:

       return $http.get("/api/stuffs/")
         .then(function(response) { // line 15
             return response.data;
       });

How do I mock this correctly? 如何正确模拟呢?

Edit: I read the documentation mentioned in the comments and and changed up mockBaseService to this: 编辑:我阅读了注释中提到的文档,然后将mockBaseService更改为:

describe('Controller: AuthCtrl', function() {
    var ctrl, mockBaseService;

    beforeEach(function() {
        // create promise
        var deferred = $q.defer();
        var promise = deferred.promise;
        // make promise.then return {stuffs: "stuffs"}
        promise.then(function(value) { return {stuffs: "stuffs" };  });

        mockBaseService = {
            stuffs: 'stuffs',
            fetch: { 
                stuffs: function() {
                    return promise;
                },
            },
        };

        spyOn(mockBaseService.fetch, 'stuffs');

        module('BaseApp', function($provide) {
            $provide.value('BaseService', mockBaseService);
        });

        module('AuthenticationApp');

        inject(function($controller) {
            ctrl = $controller('AuthCtrl', {
            });
        });
    });

    it('BaseService.fetch.stuffs should be called on page load', inject(function($rootScope) {
        deferred.resolve('test');
        $rootScope.$apply();
        expect(mockBaseService.fetch.stuffs).toHaveBeenCalled();
        expect(ctrl.stuffs).toBe({stuffs: "stuffs"});
    }));

});

But this returns a ReferenceError: $q is not defined error. 但这会返回ReferenceError: $q is not defined错误。 I tried injecting _$q_ like so: 我尝试像这样注入_$q_

beforeEach(inject(function(_$q_) {
    $q = _$q_;
    // ... everything else goes here... //

But then I get an error saying Error: Injector already created, can not register a module! 但是然后我收到一条错误消息,提示Error: Injector already created, can not register a module! . Here: injector already created. 此处: 喷油器已创建。 can not register a module it says this issue can be solved if we do module('someApp') before inject($someDependency) . 无法注册一个模块,它说如果我们在inject($someDependency)之前执行module('someApp') ,则可以解决此问题。 But I can't do 但是我做不到

module('BaseApp', function($provide) {
    $provide.value('BaseService', mockBaseService);
});

before injecting _$q_ since $q is used for mockBaseService . 在注入_$q_之前,因为$q用于mockBaseService Where do I go from here? 我从这里去哪里?

to mock promises I always do 嘲笑我一直都在做

1) spyOn(service,'method').andCallFake( $q.when( Fixture.data() ) )

Do not create that mockBaseService, I've done that before and its a lot to write for nothing It's also possible to use AngularJS built in way of intercepting $http ie 不要创建那个模拟数据库服务,我之前已经做过了,而且很多事情都没有写。也可以使用以拦截$ http的方式构建的AngularJS。

2) $httpBackend.when('GET', '/url').respond(Fixture.data())

I definitely prefer 1) as I like to isolate myself in a certain layer when doing testing. 我绝对喜欢1),因为我喜欢在进行测试时将自己隔离在特定的层中。 It comes down to a matter of taste I guess 我想这取决于口味

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM