typescript - @angular/common/http get-Metodu, sağlanan <type> ile Observable döndürmüyor - o tipe instanceof kullanımı başarısız oluyor
Bu benim Service sınıfı job.service.ts dosyam. Temelde bir Express uygulamasını çağırıyor ve sonuç olarak bir Job nesnesi alıyor. Bunu getJob() metodunu çağırana Observable olarak döndürüyor.
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));
})
}
}
}
Bu, JobService test sınıfımdan bir spesifikasyondur. spyOn yöntemi ile gerçek API'yi çağırma girişimlerinin her birini engelliyor ve görünüşe göre bir Job örneği olan sahte bir yanıt döndürüyorum. 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();
});
})
})
Eğer yürütürsem
expect(value instanceof Job).toBeTrue();
test başarısız oluyor çünkü görünüşe göre değer Job örneği değil. Eğer JobServices getJob() fonksiyonunu değiştirirsem ve şöyle manuel olarak oluşturulmuş bir Observable döndürürsem:
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));
})
}
}
Test çalışıyor! Öyleyse sorun, HttpClient kütüphanesinin get() metodunun, olması gerektiği gibi bir Observable içinde yanıtı uygun türde sağlamaması neden?
Bunu okumak için zaman ayırdığın ve herhangi bir yardımın için minnettarım!
Cevap #1
Problem 1: Test verilerinin yanlış kurulması
Testinizde oluşturduğunuz job, Job sınıfının bir örneği değildir:
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
Problem 2: http.get hakkında yanlış varsayımlar
Bu yaygın bir tuzaktır - http.get<T> sadece bir kolaylık sağlayan generiktir
http.get<T> ayrıştırılmış json nesnesini döndürür.
T yalnızca kolaylık sağlamak için kullanılır, beklenti verinizin şeklini doğru bir şekilde tanımlamasıdır. Ancak hiçbir çalışma zamanı kontrolü yapılmaz - eksik özellikler, ek özellikler, hiçbir şey kontrol edilmeyecek (ve veriye eriştiğinizde daha sonra çalışma zamanında başarısız olabilir).
Özellikle, eğer T bir sınıf ise, sorunlarla karşılaşmanız kaçınılmazdır, çünkü döndürülen veri çalışma zamanında T'nin örneği olmayacaktır - alanlar, isimler eşleşirse doldurulmuş olabilir, ancak prototip zinciri kurulmamıştır. Bu, demektir ki
- metot çağrıları çalışma zamanında başarısız olacak
- instanceof kontrolü başarısız oldu
Çözüm
http.get ile elde edilen verilerin şeklini modellemek için bir sınıf kullanmayın. Bunun yerine bir tür (veya arayüz) kullanın. Eğer bir sınıfa ihtiyacınız varsa, döndürülen verileri eşleştirin.
