Angular 2 测试 - 异步函数调用 - 何时使用

Posted

技术标签:

【中文标题】Angular 2 测试 - 异步函数调用 - 何时使用【英文标题】:Angular 2 Testing - Async function call - when to use 【发布时间】:2017-02-28 19:38:46 【问题描述】:

在 Angular 2 中进行测试时,您什么时候使用 TestBed 中的异步功能?

你什么时候用这个?

 beforeEach(() => 
        TestBed.configureTestingModule(
            declarations: [MyModule],
            schemas: [NO_ERRORS_SCHEMA],
        );
    );

你什么时候用这个?

beforeEach(async(() => 
    TestBed.configureTestingModule(
        declarations: [MyModule],
        schemas: [NO_ERRORS_SCHEMA],
    );
));

谁能告诉我这个?

【问题讨论】:

【参考方案1】:

当您在测试中进行异步调用时,实际测试功能在异步调用完成之前完成。 当您需要在调用完成时验证某些状态(通常是这种情况)时,测试框架会在异步工作仍在进行时将测试报告为已完成。

使用async(...) 可以告诉测试框架等到返回承诺或可观察对象完成后再将测试视为已完成。

it('should show quote after getQuote promise (async)', async(() => 
  fixture.detectChanges();

  fixture.whenStable().then(() =>  // wait for async getQuote
    fixture.detectChanges();        // update view with quote
    expect(el.textContent).toBe(testQuote);
  );
));

传递给then(...) 的代码将在测试函数本身完成后执行。 使用async(),您可以让测试框架意识到,在将测试视为已完成之前,它需要等待 Promise 和 observables 完成。

另见

https://angular.io/guide/testing#async

【讨论】:

变成了angular.io/api/core/testing/waitForAsync,可能是因为 async 现在是一个模棱两可的名字(Promises)。【参考方案2】:

async 将不允许下一个测试开始,直到 async 完成其所有任务。 async 所做的是将回调包装在一个区域中,在该区域中跟踪所有异步任务(例如 setTimeout)。所有异步任务完成后,async 就完成了。

如果你曾经在 Angular 之外使用过 Jasmine,你可能已经看到 done 被传递给回调

it('..', function(done) 
  someAsyncAction().then(() => 
    expect(something).toBe(something);
    done();
  );
);

这里是原生 Jasmine,我们告诉 Jasmine 这个测试应该延迟完成,直到我们调用 done()。如果我们不调用 done() 而是这样做:

it('..', function() 
  someAsyncAction().then(() => 
    expect(something).toBe(something);
  );
);

测试甚至会在预期之前完成,因为承诺会在测试完成执行同步任务之后解决。

使用 Angular(在 Jasmine 环境中),当我们使用 async 时,Angular 实际上会在后台调用 done。它将跟踪 Zone 中的所有异步任务,当它们全部完成后,done 将在后台被调用。

在您使用TestBed 配置的特定情况下,当您想要compileComponents 时,通常会使用它。我很少遇到我不得不调用它的情况

beforeEach(async(() => 
   TestBed.configureTestingModule(
     declarations: [MyModule],
     schemas: [NO_ERRORS_SCHEMA],
   )
   .compileComponent().then(() => 
      fixture = TestBed.createComponent(TestComponent);
   );
));

当测试一个使用templateUrl的组件时(如果你没有使用webpack),那么Angular需要发出一个XHR请求来获取模板,所以组件的编译是异步的。所以我们应该等到它解决后再继续测试。

【讨论】:

很好的答案@peeskillet。只是为了确保我理解它:当你有一个内联模板时,async 不是必需的。当您使用templateUrl 时,它是。但是,包含async 不会“破坏”内联模板组件。您认为可以安全地说,每次测试都默认使用async @vincecampanale templateUrl 仅在 beforeEach 中的配置过程中很重要。在这种情况下,您需要致电compileComponents。如果这是您所要求的,则与在每个测试中使用 async 无关。就安全而言(当您应该致电 compileComponents 时),请参阅 When am I supposed to call compileComponents @vincecampanale 您并不总是希望在测试之前调用它。有时您可能想在进行一些初始化后调用它。您需要了解调用它的实际作用。不过大多数时候应该没问题。但我个人不喜欢他们自己做出这个决定。但是我看到很多人遇到了忘记调用它的问题,他们想知道为什么有些东西不起作用。因此,也许他们确实生成呼叫会更好。这个位置可能有争议,但至少他们称之为 @vincecampanale 通常,当您想要(重新)渲染视图时,您应该调用它。例如创建组件 -> 渲染视图。但是,如果您想首先初始化一些东西,例如创建组件-> 更改用于渲染的组件中的值-> 渲染视图。这就是我的意思,也许你想先初始化一些东西 哦,还有一件事。第一次调用它是在组件中的ngOnInit 被调用时。有时这在测试时很重要

以上是关于Angular 2 测试 - 异步函数调用 - 何时使用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2调用多个异步方法

等待异步函数在 Angular 中完成

Angular 2+,异步测试和 setTimeout

Angular 5:无法使用异步管道更新模板

Angular - 单元测试间谍无法识别该函数已被调用

预期 = 1,接收 = 0 - 为啥我的函数没有在 Angular 测试中调用?