Тестирование устройств Angular Служба, использующая $timeout с часами Jasmine Mock
У меня есть функция внутри одной из моих служб angular, которую я бы хотел повторять с регулярным интервалом. Я хотел бы сделать это, используя $timeout. Это выглядит примерно так:
var interval = 1000; // Or something
var _tick = function () {
$timeout(function () {
doStuff();
_tick();
}, interval);
};
_tick();
Я в тупике о том, как unit test это с Жасмином на данный момент - Как это сделать? Если я использую $timeout.flush()
, то вызовы функций выполняются бесконечно. Если я использую часы Jasmine mock, $timeout
, кажется, не затронут. В принципе, если я смогу получить эту работу, мне должно быть хорошо идти:
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();
});
});
Эти два варианта работают, но не помогают мне:
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();
});
});
Спасибо заранее!
Ответы
Ответ 1
Не проводите тест Async, используя часы Jasmine. Вместо этого используйте $timeout.flush()
для синхронного поддержания потока теста. Это может быть немного сложно настроить, но как только вы его получите, ваши тесты будут более быстрыми и контролируемыми.
Вот пример теста, который использует этот подход:
https://github.com/angular/angular.js/blob/master/test/ngAnimate/animateSpec.js#L618
Ответ 2
@matsko ответ привел меня по правильному пути. Я думал, что опубликую свое "полное" решение, чтобы было проще найти ответ.
Вещь для проверки
angular.module("app").service("MyService", function() {
return {
methodThatHasTimeoutAndReturnsAPromise: function($q, $timeout) {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve(5);
}, 2000);
return deferred.promise;
}
};
});
Тест
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();
});
});