首页 > 解决方案 > Angular http get response in observable 在单元测试中不是类型转换

问题描述

我正在尝试学习角度内置单元测试。

我有使用 http.get 进入映射的方法的服务,并返回类型化的可观察流 (Observable<BankAccountFull[]>)。

但是,当我尝试使用 angular.io“测试服务”页面中的逻辑对其进行测试时,我不断收到错误消息Expected $[0] to be a kind of BankAccountFull, but was Object({...

尝试在测试的箭头函数参数和期望内部进行类型转换。

服务代码:

import { Injectable } from '@angular/core';
import { catchError, map } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import { BankAccountFull } from '../types/bank-account';
import { Observable, of } from 'rxjs';
import { ACCOUNTTYPES, AccountType } from '../types/account-type';
import { TankType, TANKTYPES } from '../types/tank-type';
import { AccList } from '../types/acc-list';

@Injectable({
  providedIn: 'root'
})
export class BankAccountService {
  private accountsUrl = 'api/accounts';

  constructor(private http: HttpClient) { }

  getAccountList(token: string): Observable<BankAccountFull[]> {
    return this.http.get<BankAccountFull[]>(this.accountsUrl)
    .pipe(
      map(response => {
        const accounts: BankAccountFull[] = response as BankAccountFull[];
        return accounts.map((item) => {
          const temp: AccountType = ACCOUNTTYPES.find(el => el.id === item.accType);
          const tempRes: BankAccountFull = {...item};
          if (temp.id) {
            tempRes.accTypeHint = temp.hint;
            tempRes.accTypeImg = temp.img;
          }
          const tempTank: TankType = TANKTYPES.find(el => el.id === item.tankType);
          if (tempTank.id) {
            tempRes.tankTypeImg = tempTank.img;
            tempRes.tankTypeName = tempTank.name;
          }
          return tempRes;
        }
      );
      }),
      catchError(this.handleError<BankAccountFull[]>('getHeroes', []))
    );
  }

  private handleError<T>(operation = 'operation', result?: T): (error: any) => Observable<T> {
    return (error: any): Observable<T> => {
      console.error(error);
      return of(result as T);
    };
  }
}

单元测试代码:

import { BankAccountService } from './bank-account.service';
import { BankAccountFull } from '../types/bank-account';
import { of } from 'rxjs';
import { HttpClient } from '@angular/common/http';

describe('BankAccountService', () => {
  let httpClientSpy: {get: jasmine.Spy};
  let service: BankAccountService;

  beforeEach(() => {
    httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);    
    service = new BankAccountService(httpClientSpy as any);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should return expected accounts list', () => {
    const expectedAccList: BankAccountFull[] = 
      [
        new BankAccountFull(true, 1, '068985 2563', 1, 500000, 0,  
          '../../assets/img/acc-types/mortgage.png', 'Mortgage', '../../assets/img/tank-types/property-tank.png', 'Property Tank'),
        new BankAccountFull(false, 2, '068985 2563', 1, 500000, 0,  '../../assets/img/acc-types/mortgage.png', 'Mortgage', 
          '../../assets/img/tank-types/property-tank.png', 'Property Tank'),
        new BankAccountFull(false, 3, '068985 2563', 2, 50000, 1, '../../assets/img/acc-types/car-loan.png', 'Car loan', 
          '../../assets/img/tank-types/property-tank.png', 'Work Tank'),
        new BankAccountFull(false, 4, '068985 2563', 3, 50000, 1, '../../assets/img/acc-types/personal-loan.png', 'Personal credit', 
          '../../assets/img/tank-types/property-tank.png', 'Work Tank'),
      ];

    httpClientSpy.get.and.returnValue(of(expectedAccList));

    service.getAccountList('someMD5Token').subscribe(
      (accList: BankAccountFull[]) => expect(accList as BankAccountFull[]).toEqual(expectedAccList, 'expected accounts list'),
      fail
    );
  });
});

测试总结:

BankAccountService > should return expected accounts list
Expected $[0] to be a kind of BankAccountFull, but was Object({ active: true, id: 1, name: '068985 2563', accType: 1, balance: 500000, tankType: 0, accTypeImg: '../../assets/img/acc-types/mortgage.png', accTypeHint: 'Mortgage', tankTypeImg: '../../assets/img/tank-types/property-tank.png', tankTypeName: 'Property Tank' }).
Expected $[1] to be a kind of BankAccountFull, but was Object({ active: false, id: 2, name: '068985 2563', accType: 1, balance: 500000, tankType: 0, accTypeImg: '../../assets/img/acc-types/mortgage.png', accTypeHint: 'Mortgage', tankTypeImg: '../../assets/img/tank-types/property-tank.png', tankTypeName: 'Property Tank' }).
Expected $[2] to be a kind of BankAccountFull, but was Object({ active: false, id: 3, name: '068985 2563', accType: 2, balance: 50000, tankType: 1, accTypeImg: '../../assets/img/acc-types/car-loan.png', accTypeHint: 'Car loan', tankTypeImg: '../../assets/img/tank-types/property-tank.png', tankTypeName: 'Work Tank' }).
Expected $[3] to be a kind of BankAccountFull, but was Object({ active: false, id: 4, name: '068985 2563', accType: 3, balance: 50000, tankType: 1, accTypeImg: '../../assets/img/acc-types/personal-loan.png', accTypeHint: 'Personal credit', tankTypeImg: '../../assets/img/tank-types/property-tank.png', tankTypeName: 'Work Tank' }).

标签: angulartypescriptunit-testingrxjsjasmine

解决方案


您应该使用HttpTestingControllerHttp Requests 进行单元测试,它有更好的 API ( https://medium.com/better-programming/testing-http-requests-in-angular-with-httpclienttestingmodule-3880ceac74cf )。

至于您为什么会看到该错误,我怀疑该行将const tempRes: BankAccountFull = {...item};类型更改为tempResto Object。这是一本很好的读物,我认为您面临着类似的情况:https ://ultimatecourses.com/blog/ngrx-store-testing-actions ( Expected object to be a kind of Object, but was LoadPizzas.)


推荐阅读