【问题标题】:Unit testing angular 11 service stub problem单元测试 Angular 11 服务存根问题
【发布时间】:2021-01-01 16:50:31
【问题描述】:

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

component.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: Cannot read property 'length' of undefined”

【问题讨论】:

    标签: angular unit-testing karma-jasmine angular-test


    【解决方案1】:

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

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

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

    然后它继续到this.currencyList.sort 由于then 块仍在排队并且promise 仍未解决,因此没有分配给currencyList,因此它包含undefined 或在启动时分配给它的任何内容。它在undefined 上调用sort 方法。由于undefined 没有sort 方法,所以会抛出错误。

    如果您正在使用 async/await,为什么要调用 then?这就是应该如何以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);
    });
    

    【讨论】:

    • 谢谢!无论如何,测试期望在这个 ngOnInit.then 中是不可见的。甚至测试名称都说“SPEC HAS NO EXPECTATIONS 应该在列表中包含货币”
    • 尝试使用 async/await(更新示例),另一种选择是在 then 块内调用 done 回调
    【解决方案2】:

    getCurrencyCodesList() 方法是异步的,当你运行this.currencyList.sort 时,this.currencyList 还没有收到data,它还不是一个数组,因此没有sort() 函数

    你可以做的是将Array类型设置为currencyList

    private currencyList: any []
    

    【讨论】:

    • 改成private会带来更多的问题。我也不能像 expect(component.currencyList.length).toBeGreaterThan(1) 那样运行 - 因为 currencyList 不可访问...还尝试了 curencyList: any[] = [] 等。
    • 隐私不是必需品,我只是出于习惯。如果你在.then()里面调用sort()不会给你这个错误,只是不知道能不能解决你的问题
    • 哦,是的,这回答了所描述的问题。不幸的是,我仍然无法运行 expect(component.currencyList.length).toBeGreaterThan(1); - 说它是未定义的
    猜你喜欢
    • 2017-12-20
    • 2019-05-06
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    相关资源
    最近更新 更多