【问题标题】:Testing async HTTP-based function with Jasmine and await: Expected one matching request for criteria "...", found none使用 Jasmine 和 await 测试基于 HTTP 的异步函数:预期有一个对条件“...”的匹配请求,但没有找到
【发布时间】:2020-09-12 09:59:34
【问题描述】:

什么:测试一个使用 await 的异步函数

使用:Angular 9,Jasmine 3.4.0

重现的最少代码:StackBlitz

我有这样的功能。请注意,它必须等待 this.getHeaders()。每当我删除 await 并用一些同步实现替换 getHeaders() 的实现时,测试就会成功运行。

测试的正确方法是什么?

private async loadUserData() {
    // Try to remove await - the test runs successfully
    //const headers = this.getHeaders();
    const headers = await this.getHeaders();
    return this.httpClient
      .get<UserData>(window.location.origin + '/12345', { headers })
      .toPromise()
      .then((data) => {
        this.userData = data;
      })
      .catch((e) => {
        console.log('Oh noooo...');
      });
  }

我的尝试:

  • 可能是 StackBitz 中的 url 不正确,但是 在本地测试时我确定它是,所以这不应该是根 原因
  • 不确定,如果 fakeAsync() 会有所帮助 - “纯”http 测试有效...

不是欺骗:

【问题讨论】:

    标签: angular testing async-await jasmine


    【解决方案1】:

    你很亲密。您的测试现在结构正确,但您需要 Angular 提供的一些测试实用程序来确保您的 Promise 以正确的顺序解决,从而使您的期望正确。

    最终问题与 Angular 区域有关。因为您在服务中构建承诺,并且承诺解决必须在传出请求发生之前发生。你在你的测试中调用loadUserData,然后在下一行你写一个断言说“确保这个请求发生了,如果不是那是一个错误”。当您以不使用异步原语(如PromiseObservable)的方式编写标头检索函数时,此请求“立即”发生。但是当您使用Promise 时,不会“立即”发生请求。相反,它必须先解决您的标头检索功能。

    幸运的是,您的测试失败只是测试环境的幻像功能,而不是您的实施中的错误。就像我说的,Angular 为你提供了一些测试工具,以确保你可以在编写断言之前“刷新”所有待处理的 Promise。

    import { fakeAsync,  tick } from '@angular/core/testing';
    
    // instead of using `done`, which is just fine btw, we wrap our test function
    // in fakeAsync(). This let's us have fine grained control over stepping through
    // our code under test
    it('should return user data on success', fakeAsync(() => {
      const mockUserData : UserData = {
        name: 'John',
          surname: 'Do',
          id: '12345'
        };
    
        (service as any).loadUserData().then(() => {
          expect((service as any).userData).toEqual(mockUserData);
          //expect(req.request.method).toEqual('GET');
        });
    
        // tick() steps through the next round of pending asynchronous activity
        // this will also step through 'setTimeout' and 'setInterval' code
        // you may have in your service, as well as Observable code
        tick();
        const req = httpTestingController.expectOne(
          'https://testing-qh48mg.stackblitz.io/12345',
        );
        req.flush(mockUserData);
    }));
    

    更新StackblitzfakeAsync 上的文档。 Related question on testing Http code in Angular using tick.

    【讨论】:

    • 非常感谢!这对我有用。下一级 - 测试更深的嵌套 - 我有一个函数在 http-request 的 then() 部分额外等待(在将其转换为 promise 之后): return this.http .get(this.requestUrl, { headers, responseType : 'text' }) .toPromise() .then(async (url) => { const someThing = await this.someFunction(); 将深入研究 tick() 和 fakeAsync...
    猜你喜欢
    • 2021-02-20
    • 2018-11-18
    • 2023-03-22
    • 2018-12-07
    • 1970-01-01
    • 2019-01-08
    • 1970-01-01
    • 2019-07-18
    • 1970-01-01
    相关资源
    最近更新 更多