@angular/common/http get-Method 不使用提供的 <type> 返回 Observable - 该类型的实例失败

问题描述

这是我的服务级 job.service.ts。它基本上是调用一个 Express 应用程序并获得一个 Job-object 作为结果。它作为 Observable 返回给 getJob() 方法调用者。

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 测试类的规范。使用 spyOn 方法,我拦截了每次调用真实 API 的尝试并返回一个假响应,这显然是 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() 函数并返回一个手动创建的 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 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> 返回解析后的 json 对象。

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

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

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

解决方案

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...