Async / FakeAsync会在spec块中等待.then还是只在它正在测试的组件/类中?

时间:2017-12-02 04:14:38

标签: angular unit-testing asynchronous jasmine

在我的业力 - 果酱测试之一仍然通过此代码后,我有点担心。

// before each above
comp = fixture.componentInstance

// This spec passes
it(`should not pass because async activity?`, () => {
    comp.router.navigate(['home']).then(() => {
        expect(true).toBe(true); // should not execute?
        // Should only execute if I placed done()?
    });
});

当我们使用像async / fakeAsync包装器这样的东西时,我认为.then()没问题

示例代码取自angular docs:

  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);
    });
  }));

虽然这段代码也没有任何包装器传递:

it(`should also not pass?`, () => {
    fixture.whenStable().then(() => {
      expect(true).toBe(true); // But it passes!! : /
    });
  });

所以这让我相信async / fakeAsync包装器可能只是用于拦截我们正在测试的组件/类中的异步活动,并且对我们正在测试的规范没有做任何事情。

任何人都可以验证为什么.then异步代码在没有done()函数的情况下对jasmine规范执行?为什么我们可以这样做,并且在没有添加done()函数的情况下它是否真的安全?

更新

感谢下面的评论:

我做了一个期望(假).toBe(true)和

// This spec fails showing that the then in router executes
it(`should not pass because async activity?`, () => {
    comp.router.navigate(['home']).then(() => {
        expect(true).toBe(true); // should not execute?
        // Should only execute if I placed done()?
    });
});
// The then is skipped and spec passes (This should be expected ^^)
it(`then here is skipped without async wrapper`, () => {
  fixture.whenStable().then(() => {
    expect(false).toBe(true); // But it passes!! : /
  });
});

所以我很高兴看到.whenStable()在没有包装器的情况下跳过了那个。还是有点关注router.then()

2 个答案:

答案 0 :(得分:0)

async是一个包装器,用于标记调用该函数的人,警告他们该函数包含异步代码。我担心我无法解释你的测试中异步的差异,但我想我可以解释你对完成功能的困惑。

首先让我清理其他东西,你的第一次和第三次测试总是会通过。请记住,空测试通过:

it(`passes`, () => {
});

因此,如果你添加一个期望应该通过的if语句,那么测试将传递if语句是否为真。

it(`still passes`, () => {
  if (21 < 42) {
    expect(true).toBe(true);
  }
});

如果要使用带有茉莉花测试的done函数,则需要将其作为参数传递给测试。以下是几个例子:

it(`passes because done in wrong place`, (done) => {
  setTimeout(() => {
     expect(false).toBe(true);
  }, 500);
  done();
});

it(`correctly does not pass as expect trigered`, (done) => {
  setTimeout(() => {
     expect(false).toBe(true);
     done();
    }, 500);
});

请记住,除非您更改jasmine.DEFAULT_TIMEOUT_INTERVAL,否则Jasmine将在5秒后超时任何测试。

您希望使用done函数让Jasmine知道您的测试已完成。我不确定它是否真的需要,但我想可能有一个论点,它可以使用稍微更具可读性的回调函数进行测试。

答案 1 :(得分:0)

asyncfakeAsync依赖于区域,他们会等待属于规范的区域中评估的异步代码。如果在组件内部或内部规范函数中创建了承诺,只要它保留在区域内就没有关系。

  it(`passes with Zone.js`, () => {
    Promise.resolve().then(() => {
      expect(true).toBe(true);
    });
  });

有效,因为Jasmine已修补以使用Zone.js并支持async / fakeAsync帮助程序,并导致与原始行为不兼容的行为。当履行承诺与then链接时,即使没有async,也可能会检测到期望并且规范订单将被保留,但不应依赖此行为。

  it(`fails with Zone.js`, () => {
    new Promise(resolve => setTimeout(resolve)).then(() => {
      expect(true).toBe(true);
    });
  });

将在Zone.js中失败。

如果没有修补Jasmine,这两个例子都无法发现期望。

一个好的做法是始终从异步规范返回一个promise(Jasmine 2.7及更高版本支持不带async / fakeAsync助手的promise返回:

it(`should not pass because async activity?`, async () => {
    await comp.router.navigate(['home']);
    expect(true).toBe(true);
});