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

时间:2022-08-24 22:34:41

I have a small Angular service that handles asynchronous rate-limiting of other functions, similar to this example. Since the main purpose of this class is to moderate asynchronous behaviors, I'd like to be able to test this service asynchronously - I won't be able to prove that this class is working with a purely synchronous test.

我有一个小的角度服务,它处理其他函数的异步限速,类似于这个示例。由于这个类的主要目的是适度的异步行为,所以我希望能够异步地测试这个服务——我无法证明这个类使用的是纯同步测试。

If I understand correctly, when Angular's ngMock module is loaded, the built-in $timeout service is replaced with a mocked version of $timeout which allows tests to synchronously run functions that are ordinarily asynchronous. However, in this case, I'd like to use the real implementation of $timeout instead of the mocked version.

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

How can I inject the real implementation of $timeout into my unit test?

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

Here's what my tests looks like currently (I'm writing my tests in 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);
    });

});

When I run this test, Karma complains that the test too took long because the mocked$timeout service never actually kicks off its deferred timeout:

当我运行这个测试时,Karma会抱怨测试耗时太长,因为模拟的$timeout服务从来没有真正启动它的延迟超时:

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

错误:Timeout . Async回调在jasmin . default_timeout_interval指定的超时内没有被调用。

1 个解决方案

#1


2  

You need to call $timeout.flush(); to force all $timeout inside your controller to be released :

需要调用$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();
});

Everything better explain here :)

这里有更好的解释:)

In addition, you should never use the real $timeout because it will REALLY slowing down your tests...

此外,您不应该使用真正的$timeout,因为它会真正地减慢您的测试……

#1


2  

You need to call $timeout.flush(); to force all $timeout inside your controller to be released :

需要调用$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();
});

Everything better explain here :)

这里有更好的解释:)

In addition, you should never use the real $timeout because it will REALLY slowing down your tests...

此外,您不应该使用真正的$timeout,因为它会真正地减慢您的测试……