jasmine:在jasmine.DEFAULT_TIMEOUT_INTERVAL指定的超时时间内未调用异步回调

时间:2014-03-24 08:48:17

标签: angularjs unit-testing debugging asynchronous jasmine

我有一个名为requestNotificationChannel的角度服务:

app.factory("requestNotificationChannel", function($rootScope) {

    var _DELETE_MESSAGE_ = "_DELETE_MESSAGE_";

    function deleteMessage(id, index) {
        $rootScope.$broadcast(_DELETE_MESSAGE_, { id: id, index: index });
    };

    return {
       deleteMessage: deleteMessage
    };

});

我正在尝试使用jasmine对此服务进行单元测试:

"use strict";

describe("Request Notification Channel", function() {
    var requestNotificationChannel, rootScope, scope;

    beforeEach(function(_requestNotificationChannel_) {
        module("messageAppModule");

        inject(function($injector, _requestNotificationChannel_) {
            rootScope = $injector.get("$rootScope");
            scope = rootScope.$new();
            requestNotificationChannel = _requestNotificationChannel_;
        })

        spyOn(rootScope, '$broadcast');
    });


    it("should broadcast delete message notification", function(done) {

        requestNotificationChannel.deleteMessage(1, 4);
        expect(rootScope.$broadcast).toHaveBeenCalledWith("_DELETE_MESSAGE_", { id: 1, index: 4 });
        done();       
    });
});

我读到了Jasmine中的异步支持,但由于我对使用javascript的单元测试不熟悉,因此无法使其正常工作。

我收到错误:

Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL

我的测试执行时间太长(约5秒)。

有人可以通过一些解释帮我提供我的代码的工作示例吗?

17 个答案:

答案 0 :(得分:200)

it函数中使用参数(下面的代码中为done)将导致Jasimne尝试异步调用。

//this block signature will trigger async behavior.
it("should work", function(done){
  //...
});

//this block signature will run synchronously
it("should work", function(){
  //...
});

done参数的命名并没有什么区别,它的存在才是最重要的。我从太多的副本/面食中遇到了这个问题。

Jasmin Asynchronous Support文档注意到参数(上面名为done)是一个回调,可以调用它让Jasmine知道异步函数何时完成。如果您从未打过电话,Jasmine将永远不会知道您的测试已经完成并最终会超时。

答案 1 :(得分:18)

在初始化服务/工厂或其他任何情况时,也可以通过省略注入来引起此错误。例如,可以通过这样做抛出它:

var service;
beforeEach(function(_TestService_) {
    service = _TestService_;
});

要修复它,只需使用inject包装函数以正确检索服务:

var service;
beforeEach(inject(function(_TestService_) {
    service = _TestService_;
}));

答案 2 :(得分:8)

import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';

使用 fakeAsync

beforeEach(fakeAsync (() => {

//your code

}));



describe('Intilalize', () => {
        it('should have a defined component', fakeAsync(() => {
            createComponent();
            expect(_AddComponent.ngOnInit).toBeDefined();
        }));
    });

答案 3 :(得分:5)

这个错误对我来说是开始的,在一直有效的测试中。在我注意到我的Macbook运行缓慢之前,我无法找到任何有用的建议。我注意到CPU被另一个进程挂起,我杀了它。 Jasmine异步错误消失了,我的测试再次正常。

不要问我为什么,我不知道。但在我的情况下,似乎缺乏系统资源。

答案 4 :(得分:3)

这更多的是观察,而不是答案,但它可能会对像我一样沮丧的其他人有所帮助。

我一直从套件中的两个测试中得到此错误。我以为我只是用我的重构破坏了测试,所以在撤消更改不起作用之后,我又恢复到了早期的代码,两次(返回两次修订)都认为它可以消除错误。这样做并没有改变。昨天整天和今天早上的一部分时间,我都追不着尾巴。

今天早上,我感到沮丧,并把代码签到了笔记本电脑上。运行了整个测试套件(约180个测试),没有错误。因此,错误永远不会出现在代码或测试中。回到我的开发箱并重新启动它,以清除内存中可能引起问题的所有内容。没有变化,在相同的两个测试中出现相同的错误。因此,我从计算机中删除了该目录,然后将其检出。瞧!没有错误。

不知道是什么原因引起的,或如何修复它,但是删除了工作目录并检出它已经修复了。

希望这对某人有帮助。

答案 5 :(得分:3)

不要使用done,只需将函数调用留空即可。

答案 6 :(得分:2)

beforeAll函数中期待某些内容时,您也会遇到此错误!

describe('...', function () {

    beforeAll(function () {
        ...

        expect(element(by.css('[id="title"]')).isDisplayed()).toBe(true);
    });

    it('should successfully ...', function () {

    }
}

答案 7 :(得分:2)

在我的情况下,这个错误是由于“fixture.detectChanges()”的使用不当引起的。似乎这个方法是一个事件监听器(async),它只会在检测到更改时响应回调。如果未检测到任何更改,则不会调用回调,从而导致超时错误。希望这会有所帮助:)

答案 8 :(得分:2)

您可以使用karma-jasmine插件来全局设置默认超时间隔。

在karma.conf.js中添加此配置

module.exports = function(config) {
  config.set({
    client: {
      jasmine: {
        timeoutInterval: 10000
      }
    }
  })
}

答案 9 :(得分:1)

删除scope引用和函数参数后工作:

"use strict";

describe("Request Notification Channel", function() {
    var requestNotificationChannel, rootScope;

    beforeEach(function() {
        module("messageAppModule");

        inject(function($injector, _requestNotificationChannel_) {
            rootScope = $injector.get("$rootScope");
            requestNotificationChannel = _requestNotificationChannel_;
        })
        spyOn(rootScope, "$broadcast");
    });


    it("should broadcast delete message notification with provided params", function() {
        requestNotificationChannel.deleteMessage(1, 4);
        expect(rootScope.$broadcast).toHaveBeenCalledWith("_DELETE_MESSAGE_", { id: 1, index: 4} );
    });
});

答案 10 :(得分:1)

代替

beforeEach(() => {..

使用

beforeEach(fakeAsync(() => {..

答案 11 :(得分:0)

  

正如@mastablasta所指出的,还要补充一点,如果您调用'done'参数,或者更确切地说将其命名为 completed ,则只需在测试完成后调用回调complete()即可。 / p>

// this block signature will trigger async behavior.
it("should work", function(done){
  // do stuff and then call done...
  done();
});

// this block signature will run synchronously
it("should work", function(){
  //...
});

答案 12 :(得分:0)

jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;

将其保留在区块中可以解决我的问题。

it('', () => {
 jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
});

答案 13 :(得分:0)

我所做的是:添加/更新了以下代码:

framework: 'jasmine',
jasmineNodeOpts: 
{
    // Jasmine default timeout
    defaultTimeoutInterval: 60000,
    expectationResultHandler(passed, assertion) 
    {
      // do something
    },
}

答案 14 :(得分:0)

如果done函数中有参数(it),请尝试将其删除,并在函数本身内调用:

it("should broadcast delete message notification", function(/*done -> YOU SHOULD REMOVE IT */) {

    requestNotificationChannel.deleteMessage(1, 4);
    expect(rootScope.$broadcast).toHaveBeenCalledWith("_DELETE_MESSAGE_", { id: 1, index: 4 });
    // done(); -> YOU SHOULD REMOVE IT        
});

答案 15 :(得分:0)

测试似乎正在等待永远不会出现的回调。可能是因为测试没有以异步行为执行。

首先,查看是否仅在“ it”场景中使用了fakeAsync:

it('should do something', fakeAsync(() => {

您还可以使用flush()等待microTask队列完成,或者使用tick()等待指定的时间。

答案 16 :(得分:0)

在我的例子中,超时的原因是使用 providedIn: 'root' 注入服务失败。目前尚不清楚为什么注入失败,也不清楚如果显然没有可用的提供程序实例,为什么没有早期错误。

我可以通过手动提供一个值来解决这个问题:

TestBed.configureTestingModule({
  declarations: [
    // ...
  ],
  imports: [
    // ...
  ],
  providers: [
    // ...
    { provide: MyService, useValue: { /* ... */ } },
  ]
}).compileComponents();