@angular/common/http get-Method 不 return 具有提供的 <type> 的 Observable - 该类型的 instanceof 失败

@angular/common/http get-Method does not return the Observable with the provided <type> - instanceof that type fails

这是我的服务-classjob.service.ts。它基本上是调用一个 Express 应用程序并作为结果获得一个作业对象。对于 getJob() 方法的调用者来说,它 return 是 Observable。

import { Injectable } from '@angular/core';
import {Job} from "./domain-models/Job";
import {Observable} from 'rxjs';
import {HttpClient} from "@angular/common/http";

@Injectable({
  providedIn: 'root'
})
export class JobService {

  readonly ROOT_URL = 'http://localhost:3000';
  constructor(private http: HttpClient) { }

  getJob(jobId: string): Observable<any> {
    if(jobId){
  
      return this.http.get<Job>(`${this.ROOT_URL}/jobs/${jobId}`);
    }else{
        return new Observable<Error>( subscriber => {
          subscriber.next(new Error('No jobID provided));
        })

      }
    }
  }

这是我的 JobService 测试的规范 class。使用 spyOn 方法,我拦截了所有尝试调用真实 API 和 return 的虚假响应,这显然是 Job 的一个实例。 job.service.spec.ts:

  describe('Testing the getJob() function of JobService', ()=>{


beforeEach(()=>{
      let jobId: string = 'A123456789'
      const job: Job = {
        actualCost: 100,
        amountPaid: 50,
        wishAnalysis: false
      };
      spyOn(httpService, "get").and.returnValue(of<Job>(job));
    })
 


it('should return an Observable with the corresponding job object matching the id',()=>{
      let jobIdPassed: string = 'A123456789'
      service.getJob(jobIdPassed).subscribe(value => {
        expect(value instanceof Job).toBeTrue();
      });
    })
})

如果我执行

expect(value instanceof Job).toBeTrue();

测试失败,因为 value 似乎不是 Job 的实例。如果我更改 JobServices getJob() 函数和 return 手动创建的 Observable,如下所示:

getJob(jobId: string): Observable<any> {
    if(jobId){
      return new Observable<Job>(subscriber => {
         subscriber.next(new Job());
         subscriber.complete();

      })
    }else{
        return new Observable<Error>( subscriber => {
          subscriber.next(new Error('No jobID provided));
        })

      }
    }

测试有效! 所以问题是为什么 HttpClient 库的 get() 方法没有像预期的那样在 Observable 中提供适当类型的响应?

感谢您花时间阅读本文并提供任何帮助!

问题一:测试数据设置不正确

您在测试中创建的 job 不是 Job 的实例 class:

class Job {
  constructor(public actualCost: number, 
              public amountPaid: number, 
              public wishAnalysis: boolean) {}
}

const job: Job = {
  actualCost: 100,
  amountPaid: 50,
  wishAnalysis: false
};

console.log(job);
console.log(job instanceof Job); //false

问题2:关于http.get

的错误假设

这是一个常见的陷阱 - http.get<T> 只是一个 convenience generic

http.get<T> returns 已解析 json 对象。

T 只是为了方便而使用,期望它能正确描述数据的形状。但不执行运行时检查 - 缺少属性、附加属性,不会检查任何内容(并且稍后在运行时失败,当您访问数据时)。

特别是,如果 T 是 class,您肯定会遇到问题,因为返回的数据在运行时不会是 T 的实例 - 如果名称匹配,它可能会填充字段, 但原型链未建立。这意味着

  • 方法调用将在运行时失败
  • instanceof 检查失败

解决方案

不要使用 class 来模拟使用 http.get 获取的数据的形状。 请改用类型(或接口)。如果你需要一个class,映射返回的数据。