在 Karma/Jasmine 单元测试中注入 Angular $timeout服务的真实实现

Inject real implementation of Angular's $timeout service in a Karma/Jasmine unit test

本文关键字:timeout 服务 实现 真实 Angular 注入 Karma Jasmine 单元测试      更新时间:2023-09-26

>我有一个小型的 Angular 服务来处理其他函数的异步速率限制,类似于此示例。 由于此类的主要目的是调节异步行为,因此我希望能够异步测试此服务 - 我将无法证明此类正在使用纯同步测试。

如果我理解正确,当加载 Angular 的 ngMock 模块时,内置的 $timeout 服务被替换为模拟版本的$timeout,该版本允许测试同步运行通常异步的函数。 但是,在这种情况下,我想使用 $timeout 的真正实现而不是模拟版本。

如何将$timeout的真正实现注入到我的单元测试中?

以下是我的测试目前的样子(我正在用 TypeScript 编写我的测试(:

describe('My Tests', () => {
    let myService: MyService,
        $timeout: ng.ITimeoutService;
    beforeEach(() => {
        inject(($injector) => {
            // this gets me the mocked version of $timeout
            $timeout = $injector.get('$timeout');
        });
        myService = new MyService($timeout);
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
    });
    it('should pass', (done) => {
        $timeout(50)
            .then(() => {
                // this is never called
                expect(1).toBe(1);
            })
            .finally(done);
    });
});

当我运行这个测试时,Karma 抱怨测试也花了很长时间,因为模拟的$timeout服务实际上从未启动其延迟超时:

Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

你需要调用 $timeout.flush((; 强制释放控制器内的所有$timeout:

it('a ctrl with $timeout inside', inject(function($timeout) {
    var myCOntroller = $controller('Controller', { $scope: $scope });
    // flush timeout(s) for all code under test.
    $timeout.flush();
    // this will throw an exception if there are any pending timeouts.
    $timeout.verifyNoPendingTasks();
    expect($scope.result).toBe("whatIexpect");
}));
// with your example
it('should pass', (done) => {
    $timeout(50)
        .then(() => {
            // this is never called
            expect(1).toBe(1);
        })
        .finally(done);
    $timeout.flush();
});

一切都在这里更好地解释:)

此外,您永远不应该使用真正的$timeout因为它确实会减慢您的测试速度......