Angularjs 用承诺模拟服务,以便在另一个服务中进行测试

Angularjs 用承诺模拟服务,以便在另一个服务中进行测试,angularjs,unit-testing,mocking,jasmine,promise,Angularjs,Unit Testing,Mocking,Jasmine,Promise,我有以下服务(为简单起见减少): 我希望测试maxEventTime只有在承诺成功后才设置 我的测试: describe('Service: BasicTimerService', function () { beforeEach(module('myApp')); var mockPromiseService, BasicTimerService, $q, $rootScope, deferred; b

我有以下服务(为简单起见减少):

我希望测试maxEventTime只有在承诺成功后才设置

我的测试:

describe('Service: BasicTimerService', function () {
    beforeEach(module('myApp'));

    var mockPromiseService,
        BasicTimerService,
        $q,
        $rootScope,
        deferred;

    beforeEach(function(){
        mockPromiseService = {
            maxEventTime: function() {
                return 17000;
            }
        };

        module(function($provide){
            $provide.value('PromiseService', mockPromiseService);
        });

        inject(function(_BasicTimerService_, _$q_, _$rootScope_){
            BasicTimerService = _BasicTimerService_;
            $rootScope = _$rootScope_;
            $q = _$q_;
        });

        mockPromiseService.get_promise = function() {
            var deferred = $q.defer();
            deferred.resolve('hello world');
            return deferred.promise;
        };
    });

    it('should get maxEventTime once the promise is resolved.', function() {
        spyOn(mockPromiseService, 'get_promise').and.callThrough();
        spyOn(mockPromiseService, 'maxEventTime').and.callThrough();

        $rootScope.$apply();

        BasicTimerService.start();

        expect(mockPromiseService.get_promise).toHaveBeenCalled();
        expect(BasicTimerService.get_isPlaying()).toBe(true);
        expect(mockPromiseService.maxEventTime).toHaveBeenCalled();
    });
});
我已经确定mockPromiseService.get_promise()已成功调用(第一个expect()已成功),但BasicTimerService中的.then()子句似乎未被调用,我无法找出原因

我尝试了使用
$rootScope.$apply()
以及
$rootScope.$digest()无效

关于为什么这不起作用,你有什么想法吗?

你的
start()
方法是异步的,因此如果它工作正常,
get\u isplay()
在你检查它的值时将不会是
true
。您需要等待结果(修改
start()
以返回Benjamin Grunbaum建议的承诺:

it('should get maxEventTime once the promise is resolved.', function(done) {
    spyOn(mockPromiseService, 'get_promise').and.callThrough();
    spyOn(mockPromiseService, 'maxEventTime').and.callThrough();

    $rootScope.$apply();

    BasicTimerService.start().then(function () {
        expect(mockPromiseService.get_promise).toHaveBeenCalled();
        expect(BasicTimerService.get_isPlaying()).toBe(true);
        expect(mockPromiseService.maxEventTime).toHaveBeenCalled();
        done();
    });
});
您也不需要在
get\u promise
中使用
$q.defer()
(您几乎不需要使用
$q.defer()
):


注意:根据
$q
文档,您似乎可以使用
$rootScope.$apply()
将承诺值传播到它们的
然后
处理程序,但我认为您应该将承诺视为承诺并使用
然后()
等进行测试。

开始
返回承诺。通常,如果某个执行I/O操作,它应该始终返回该io完成的承诺(或在回调版本中进行回调)。我必须将$rootScope.apply()移到测试的最后一行,但所有其他操作都按照说明进行。感谢您的帮助!
it('should get maxEventTime once the promise is resolved.', function(done) {
    spyOn(mockPromiseService, 'get_promise').and.callThrough();
    spyOn(mockPromiseService, 'maxEventTime').and.callThrough();

    $rootScope.$apply();

    BasicTimerService.start().then(function () {
        expect(mockPromiseService.get_promise).toHaveBeenCalled();
        expect(BasicTimerService.get_isPlaying()).toBe(true);
        expect(mockPromiseService.maxEventTime).toHaveBeenCalled();
        done();
    });
});
mockPromiseService.get_promise = function() {
    return $q.when('hello world');
};