简体   繁体   English

单元测试Angular Service使用$ timeout与Jasmine的模拟时钟

[英]Unit Testing Angular Service that uses $timeout with Jasmine's Mock Clock

I have a function inside one of my angular services that I'd like to be called repeatedly at a regular interval. 我在我的一个角度服务中有一个函数,我希望定期重复调用它。 I'd like to do this using $timeout. 我想用$ timeout来做这件事。 It looks something like this: 它看起来像这样:

var interval = 1000; // Or something

var _tick = function () {
     $timeout(function () {
        doStuff();
        _tick();
    }, interval);
};

_tick();

I'm stumped on how to unit test this with Jasmine at the moment - How do I do this? 我对如何用Jasmine进行单元测试感到困惑 - 我该怎么做? If I use $timeout.flush() then the function calls occur indefinitely. 如果我使用$timeout.flush()那么函数调用将无限期地发生。 If I use Jasmine's mock clock, $timeout seems to be unaffected. 如果我使用Jasmine的模拟时钟, $timeout似乎不会受到影响。 Basically if I can get this working, I should be good to go: 基本上如果我能让这个工作,我应该好好去:

describe("ANGULAR Manually ticking the Jasmine Mock Clock", function() {
    var timerCallback, $timeout;

    beforeEach(inject(function($injector) {
        $timeout = $injector.get('$timeout');
        timerCallback = jasmine.createSpy('timerCallback');
        jasmine.Clock.useMock();
    }));

    it("causes a timeout to be called synchronously", function() {
        $timeout(function() {
            timerCallback();
        }, 100);
        expect(timerCallback).not.toHaveBeenCalled();
        jasmine.Clock.tick(101);
        expect(timerCallback).toHaveBeenCalled();
    });
});

These two variations work, but do not help me: 这两个版本有用,但不能帮助我:

describe("Manually ticking the Jasmine Mock Clock", function() {
    var timerCallback;

    beforeEach(function() {
        timerCallback = jasmine.createSpy('timerCallback');
        jasmine.Clock.useMock();
    });

    it("causes a timeout to be called synchronously", function() {
        setTimeout(function() {
            timerCallback();
        }, 100);
        expect(timerCallback).not.toHaveBeenCalled();
        jasmine.Clock.tick(101);
        expect(timerCallback).toHaveBeenCalled();
    });
});

describe("ANGULAR Manually flushing $timeout", function() {
    var timerCallback, $timeout;

    beforeEach(inject(function($injector) {
        $timeout = $injector.get('$timeout');
        timerCallback = jasmine.createSpy('timerCallback');
    }));

    it("causes a timeout to be called synchronously", function() {
        $timeout(function() {
            timerCallback();
        }, 100);
        expect(timerCallback).not.toHaveBeenCalled();
        $timeout.flush();
        expect(timerCallback).toHaveBeenCalled();
    });
});

Thanks in advance! 提前致谢!

Do not make your test Async by using Jasmine's clock. 不要使用Jasmine的时钟进行测试异步。 Instead, use $timeout.flush() to synchronously maintain the flow of the test. 相反,使用$timeout.flush()来同步维护测试流程。 It may be a bit tricky to setup, but once you get it then your tests will be faster and more controlled. 设置可能有点棘手,但一旦得到它,您的测试将更快,更受控制。

Here's an example of a test that does it using this approach: https://github.com/angular/angular.js/blob/master/test/ngAnimate/animateSpec.js#L618 以下是使用此方法进行测试的示例: https//github.com/angular/angular.js/blob/master/test/ngAnimate/animateSpec.js#L618

@matsko's answer led me down the right path. @ matsko的回答让我走上了正确的道路。 I thought I'd post my "complete" solution to make it simpler to find the answer. 我以为我会发布我的“完整”解决方案,以便更容易找到答案。

The thing to test 要测试的东西

angular.module("app").service("MyService", function() {
    return {
        methodThatHasTimeoutAndReturnsAPromise: function($q, $timeout) {
            var deferred = $q.defer();
            $timeout(function() {
                deferred.resolve(5);
            }, 2000);
            return deferred.promise;
        }
    };
});

The test 考试

describe("MyService", function() {
    var target,
        $timeout;
    beforeEach(inject(function(_$timeout_, MyService) {
        $timeout = _$timeout_;
        target = MyService;
    }));
    beforeEach(function(done) {
        done();
    });
    it("equals 5", function(done) {
        target.methodThatHasTimeoutAndReturnsAPromise().then(function(value) {
            expect(value).toBe(5);
            done();
        });
        $timeout.flush();
    });
});

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

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