首页 > 解决方案 > 单元测试 Angular 11 服务存根问题

问题描述

我正在尝试对我的组件进行单元测试。

组件.ts:

async ngOnInit(): Promise<void> {
  await this.dataProviderService.getCurrencyCodesList().then(data => {
    this.currencyList = data;
  });
  this.currencyList.sort((a, b) => {
    return a.code > b.code ? 1 : -1;
  });
// ...
}

使用的服务方法:

async getCurrencyCodesList(): Promise<any[]> {
    // ...
    const currencyCodes = currencyList.map(data => {
      return {code: data.code, currency: data.currency, table: data.table};
    });

    return currencyCodes;
  }

在 spec.ts 文件中,我尝试创建一个存根

//...
it('should have currencies in the list', () => {
    expect(component.currencyList.length).toBeGreaterThan(1);
});
});
class DataProviderServiceStub {
  async getCurrencyCodesList(): Promise<Observable<any[]>> {
    return of ([{code: 'PLN', table: 'A'},
                {code: 'EUR', table: 'A'}]);
  }
}

// then this:
class DataProviderServiceStub {
  async getCurrencyCodesList(): Promise<any[]> {
    return ([{code: 'PLN', table: 'none'},
             {code: 'EUR', table: 'A'}]);
  }
} 
//also tried return (of)([]), ([{}]) etc.

问题是我在从存根获得的数组上使用 .sort 时遇到了这样的 Karma 错误:

Error: Uncaught (in promise): TypeError: this.currencyList.sort is not a function
TypeError: this.currencyList.sort is not a function

它有时会以错误的形式出现,有时会以 AfterAll 错误的形式出现,有时它会说一切都很好。我究竟做错了什么?

测试结果失败:“TypeError:无法读取未定义的属性‘长度’”

标签: angularunit-testingkarma-jasmineangular-test

解决方案


一旦 OnInit 被调用,这个块就会被执行: this.dataProviderService.getCurrencyCodesList()

接下来,then将块推送到微任务队列并安排调用:

.then(data => {
    this.currencyList = data;
  });

然后继续进行,this.currencyList.sort 因为thenblock 仍在排队并且 promise 仍未解决,因此没有分配任何内容currencyList,因此它包含undefined在启动时分配给它的任何一个或任何内容。它调用sort方法 on undefined。由于undefined没有sort方法,它会引发错误。

then如果您使用 async/await,为什么要打电话?这就是它应该如何实现的 async/await方式。

async ngOnInit(): Promise<void> {
  this.currencyList = await this.dataProviderService.getCurrencyCodesList();
  this.currencyList.sort((a, b) => {
    return a.code > b.code ? 1 : -1;
  });
// ...
}

它基本上等到getCurrencyCodesList()promise 被解决,然后将响应写入currencyList字段。然后它继续进行常规同步流程。

由于您使用的是 Promise,因此您的存根应该返回 Promise 而不是 observables。在您的情况下,我会使用 jasmine 间谍而不是存根进行测试,例如:

const localizationProviderSpy = jasmine.createSpyObj<LocalizationProviderService>('LocalizationProviderService', ['getCurrencyCodesList']);

将 spy 添加到您的提供程序列表中,您最有可能使用 TestBed,然后在您的测试用例中使用它,如下所示:

it('should have currencies in the list', async () => {
   const expected = [{code: 'PLN', table: 'A'}, {code: 'EUR', table: 'A'}];

   localizationProviderSpy
     .getCurrencyCodesList
     .and
     .returnValue(Promise.resolve(expected));

   await component.ngOnInit();

   expect(component.currencyList.length).toBeGreaterThan(1);
   expect(component.currencyList).toEqual(expected);
});

推荐阅读