如何使用Jasmine/Karma来模仿AngularJS的承诺?

如何使用Jasmine/Karma来模仿AngularJS的承诺?,angularjs,angular-promise,angular-mock,Angularjs,Angular Promise,Angular Mock,这是我的控制器: angular.module("AuthenticationApp", ["BaseApp"]) .controller("AuthCtrl", ["$http", "BaseService", function($http, BaseService) { var self = this; BaseService.fetch.stuffs() .then(function(data) { se

这是我的控制器:

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

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

    }]);
       return $http.get("/api/stuffs/")
         .then(function(response) { // line 15
             return response.data;
       });
这是my
BaseService
(我需要模拟的工厂):

我不知道从哪里开始。我尝试的是:

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"});
    });

});
但是当我测试这段代码时,我得到一个错误,说:

TypeError: Cannot read property 'then' of undefined
    at new <anonymous> (/home/user/Documents/ebdjango/ebdjangoapp/static/js/home.js:15:11)
我该如何正确地模仿这一点

编辑:我阅读了评论中提到的文档,并将
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"});
    }));

});
但这将返回一个
ReferenceError:$q未定义
错误。我试着像这样注射
\uq

beforeEach(inject(function(_$q_) {
    $q = _$q_;
    // ... everything else goes here... //
但是我得到一个错误,说
错误:注入器已经创建,无法注册模块。这里:它说如果我们在
注入($someDependency)
之前执行
模块('someApp')
,这个问题就可以解决。但我做不到

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

注入
\uq
之前,因为
$q
用于
mockBaseService
。我该从这里走到哪里?

去模仿我一直在做的承诺

1) spyOn(service,'method').andCallFake( $q.when( Fixture.data() ) )
不要创建那个mockBaseService,我以前已经做过了,它需要大量的免费编写 也可以使用内置的AngularJS拦截$http,即

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

我当然更喜欢1)因为我喜欢在做测试时把自己隔离在某一层。归根结底,我想这是一个品味的问题。

看看吧。@georgeawg谢谢。我阅读了这些链接,并尝试实现我学到的东西。你能验证我是否在正确的轨道上,以及如何解决我遇到的新错误吗?好的,谢谢。顺便说一句,在示例1中,
Fixture
Fixture.data()
到底是什么?哦,那只是我自己的事情。。。这是你回应的数据。这是一个很好的实践,但是像函数Fixture()这样的Fixture中的所有响应数据都是无效的。{this.user={name:'Adam'};this.accounts=[{balance:100}]}哦,好的。因此,我尝试执行您提到的操作(即在每个函数之前添加以下内容:函数Fixture(){…},然后将Fixture.data()传递给and.callFake($q.when(Fixture.data())),但我得到一个错误,即Fixture.data不是函数。你知道如何解决这个问题吗?这是一个jsbin,有三个选项可以用来创建一个fixture,我得到一个错误,告诉我传递给callFake的
参数应该是一个函数,当我执行
时得到[object object]
和.callFake($q.When(fixture.data())
。我正在使用第一个选项来创建夹具,但第二个选项也会给出相同的错误。编辑:根据这里的答案:可能这与
$q.when
成为函数而不是传递给
和.callFake()的值有关?我不知道如何解决这个问题。
2) $httpBackend.when('GET', '/url').respond(Fixture.data())