@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,映射返回的数据。
这是我的服务-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,映射返回的数据。