[英]Cant understand the error: TypeError: Cannot read property 'subscribe' of undefined
我編寫了一個實現來從 API 調用中獲取數據。 但是,在測試功能時,即使在編寫任何有意義的測試用例之前,我也會收到以下錯誤:
TypeError: Cannot read property 'subscribe' of undefined
at DataComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/dashboard/job/job.component.ts:48:10)
at callHook (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:3405:1)
at callHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:3375:1)
at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:3327:1)
at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8573:1)
at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8672:1)
at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9885:1)
at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9910:1)
at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10320:1)
at ComponentFixture._tick (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:243:1)
我不確定我錯過了什么,任何幫助將不勝感激。 我查看了以下內容以獲得一些理解:
和其他一些參考資料。
這是我的代碼文件。 我已經刪除了我認為與手頭的問題無關的代碼的某些部分。
dataService.ts 代碼:
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { IData } from '../model/data.model';
import { Observable, throwError } from 'rxjs';
import {catchError, tap} from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
public getData(): Observable<IData[]>{
return this.http.get<IData[]>('url')
.pipe(
tap(data => console.log('Data Received')),
catchError(this.handleError)
);
}
private handleError(err: HttpErrorResponse){
//handle error code
}
}
我正在測試的組件-> data.component.ts 代碼:
import { Component, OnInit, Input} from '@angular/core';
import { IData } from '../../model/data.model';
import {DataService} from '../../service/data.service';
@Component({
selector: 'app-job',
templateUrl: './job.component.html',
styleUrls: ['./job.component.css']
})
export class JobComponent implements OnInit {
@Input() appId: string;
jobs: IData[] = [];
constructor( private dataService: DataService ) {}
ngOnInit(): void {
this.dataService.getData().subscribe({
next: data => {
this.data = data;
},
error: err => this.errorMessage = err
});
}
//other implementation
}
測試文件:data.spec.ts:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataComponent } from './job.component';
import { IData } from 'src/app/model/job.model';
import { DataService } from 'src/app/service/job-data.service';
import { of, Observable } from 'rxjs';
import { NO_ERRORS_SCHEMA } from '@angular/core';
describe('DataComponent', () => {
let component: DataComponent;
let fixture: ComponentFixture<DataComponent>;
let mockDataService ;
let JOBS: IData[];
beforeEach(async () => {
mockJobDataService = jasmine.createSpyObj(['getData']);
await TestBed.configureTestingModule({
declarations: [ DataComponent ],
providers: [
{provide: DataService, useValue: mockDataService}
]
})
.compileComponents()
.then(() => {
DATA = [{id: 'CJH'}];
fixture = TestBed.createComponent(DataComponent);
component = fixture.componentInstance;
fixture.detectChanges(); //updates bindings
});
});
it('should return true',() => {
expect(true).toBe(true);
})
});
當我刪除fixture.detectChanges()
時,錯誤被刪除。 但據我了解,即使我在測試中的任何地方使用此調用,測試用例也應該有效。
您正在使用mockJobDataService = jasmine.createSpyObj(['getData']);
並使用此{provide: DataService, useValue: mockDataService}
正確注冊它。 此時,您的組件應該被正確地創建並注入了您的虛假服務。 問題是您沒有在假服務上設置預期的方法調用。
只要您在調用fixture.detectChanges()
之前執行此操作,類似以下的操作就可以解決問題。 由於您不包括IJob
界面的形狀,因此我無法准確告訴您,但我通過強制轉換( ({} as IJob)
)使其與 typescript 一起使用。
import { of } from 'rxjs';
mockJobDataService.getData.and.returnValue(of([({} as IJob)]));
這告訴 jasmine 任何使用這個假數據服務的東西,在調用 getData 方法時,該方法的返回值應該是of([({} as IJob)])
(這是一個 IJob 數組類型的 observable)。
隨着您前進並編寫實際測試您的組件的測試,您可能希望將模擬方法和“detectChanges”調用移動到每個測試中,以便您可以為每個測試提供不同的假數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.