Javascript 无法理解错误:TypeError:无法读取属性';订阅';未定义的
我编写了一个从API调用获取数据的实现。但是,在测试功能时,即使在编写任何有意义的测试用例之前,我也会遇到以下错误:Javascript 无法理解错误:TypeError:无法读取属性';订阅';未定义的,javascript,angular,typescript,rxjs,integration-testing,Javascript,Angular,Typescript,Rxjs,Integration Testing,我编写了一个从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 cal
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)
我不确定我错过了什么,任何帮助都将不胜感激。
我研究了以下内容以获得一些理解:
- ->解决方案在我的情况下不起作用
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.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);
})
});
从'@angular/core/testing'导入{ComponentFixture,TestBed};
从“./job.component”导入{DataComponent};
从'src/app/model/job.model'导入{IData};
从'src/app/service/job data.service'导入{DataService};
从“rxjs”导入{of,Observable};
从'@angular/core'导入{NO_ERRORS_SCHEMA};
描述('DataComponent',()=>{
let组件:数据组件;
let夹具:组件夹具;
让mockDataService;
let JOBS:IData[];
beforeach(异步()=>{
mockJobDataService=jasmine.createSpyObj(['getData']);
等待TestBed.configureTestingModule({
声明:[DataComponent],
供应商:[
{提供:DataService,useValue:mockDataService}
]
})
.compileComponents()
.然后(()=>{
数据=[{id:'CJH'}];
fixture=TestBed.createComponent(DataComponent);
组件=fixture.componentInstance;
fixture.detectChanges();//更新绑定
});
});
它('应该返回true',()=>{
期望(真),期望(真);
})
});
当我删除fixture.detectChanges()时,错误被删除。但据我所知,即使我在测试中的任何地方使用此调用,测试用例也应该可以工作。您正在使用
mockJobDataService=jasmine.createSpyObj(['getData'])创建一个spy对象代码>并正在使用此{provide:DataService,useValue:mockDataService}
正确注册它。在这一点上,您的组件应该正确地创建,并将您的伪服务注入其中。问题在于,您没有在伪服务上设置预期的方法调用
只要您在调用fixture.detectChanges()
之前这样做,下面的内容就可以解决这个问题。由于您没有包括IJob
界面的形状,我不能确切地告诉您,但我通过将其转换为(({}作为IJob)
)使其与typescript一起工作
从'rxjs'导入{of}代码>
mockJobDataService.getData.and.returnValue(of([({}as IJob)])代码>
这告诉jasmine任何使用这个伪数据服务的东西,在调用getData方法时,该方法的返回应该是of([({}as IJob)]
(这是IJob数组类型的可观察值)
当您继续编写实际正在测试组件的测试时,您可能希望将模拟方法和“detectChanges”调用移动到每个测试中,以便为每个测试提供不同的假数据。对于错误表示歉意。为了发布这个问题,我更改了组件和变量的名称,但遗漏了几个地方。将所有发生的“作业”替换为“数据”。(如JobComponent->DataComponent、JOBS->DATA等)为什么不为“mockDataService”模拟值定义一个“getData”假实现?@habibchabbi你是说这个吗?mockDataService={getData:()=>{return of(DATA);}}}是的,这不起作用吗?是的,它现在起作用了。我早些时候犯了一个愚蠢的错误。谢谢,我试过了。为我工作。谢谢
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);
})
});