mycomponent.spec.ts class:
这会引发错误:无法读取属性  ngOnInit'未定义的。
let myComponent: MyComponent;
let myService: MyService;
describe('myComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MyComponent],
providers: [
{provide: MyService, useClass: MockMyService} // **--passing Mock service**
]
}).compileComponents()
.then(() => {
myComponent = TestBed.createComponent(MyComponent).componentInstance;
myService = TestBed.get(MyService);
console.log(myService.getData());
});
});
it('should get the mock data', () => {
myComponent.ngOnInit(); //-----------> seems like myComponent is not defined at this place, how to resolve this error
expect(myComponent.data).toBe(DATA_OBJECT);
});
});
下面是MyComponent:
@Component({
selector: 'pm-catalogs',
templateUrl: './catalog-list.component.html'
})
export class MyComponent implements OnInit {
public data: IData[];
constructor(private _myService: MyService) {
}
public ngOnInit(): void {
this._myService.getData()
.subscribe(
data => this.data = data
// error => this.errorMessage = <any>error
);
}
}
下面是模拟服务
export const DATA_OBJECT: IData[] = [
{
'Id': 1,
'value': 'abc'
},
{
'Id': 2,
'value': 'xyz'
}];
@Injectable()
export class MockMyService {
public getData(): Observable<IData[]> {
return Observable.of(DATA_OBJECT);
}
}
我是Angular2测试的新手,当myComponent.ngOnInit()在我的spec类中调用myService.getData()方法时,我希望myService.getData返回DATA_OBJECT 请帮助我实现这一目标。
答案 0 :(得分:4)
您不必手动调用ngOnInit()
来运行组件的init()。
将代码修改为以下代码
let myComponent: MyComponent;
let myService: MyService;
let fixture;
describe('myComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MyComponent],
providers: [
{provide: MyService, useClass: MockMyService} // **--passing Mock service**
]
}).compileComponents()
.then(() => {
fixture = TestBed.createComponent(MyComponent);
myComponent = TestBed.createComponent(MyComponent).componentInstance;
myService = TestBed.get(MyService);
console.log(myService.getData());
});
});
it('should get the mock data', () => {
fixture.detectChanges(); // this line will call components ngOnInit() method
expect(myComponent.data).toBe(DATA_OBJECT);
});
})
查看行fixture.detectChanges();
第一次发生更改检测时,将调用组件ngOnInit()
。
答案 1 :(得分:3)
问题是异步$group->each(function($item){
array_push($bounceZoneList,$item->**the_entry_you_want_to_be_pushed_to_the_array**);
}
未正确实现,这会导致竞争条件。
在beforeEach
阻止中执行.compileComponents().then(() => { ... })
会导致beforeEach
回调中的代码执行延迟至少一次。 then
块永远不会等待并在有机会被分配之前访问it
变量。
当测试没有失败时,这种竞争条件会变得不那么明显,也会变得更加危险。相反,当先前测试的myComponent
影响当前测试中的变量时,测试可能会被交叉污染。
beforeEach
是同步的,除非有.compileComponents()
和styleUrls
的组件(如上例所示)。在这种情况下,它变为异步,并且应该使用templateUrl
帮助程序:
async
根据经验,如果块可能是异步的,则块应该使用// asynchronous block
beforeEach(async(() => {
TestBed.configureTestingModule({ ... })
.compileComponents();
}));
// synchronous block
beforeEach(() => {
myComponent = ...
});
async
帮助程序包装。
使用fakeAsync
测试组件类时,它们遵循生命周期并自动调用它们的挂钩。不需要手动调用TestBed
(正如另一个答案所解释的那样)并且将导致调用挂钩两次。
答案 2 :(得分:0)
以防万一某个人认为接受的答案没有帮助,并且如果NgZone
没有得到适当的嘲笑,此错误也可能出现。我不了解底层机制,但是a以前提供了模拟NgZone
作为对象文字,如下所示:
TestBed.configureTestingModule({
providers: [{
provide: NgZone,
useValue: {
runOutsideAngular: (fn: (...args: Array<any>) => T) => { return fn(); }
... other NgZone functions ...
}
}],
declarations: [MyComponent]
})
由于某些原因,该方法在某些测试中有效,因此我起初并不怀疑,但过了一会儿,我创建了一个模拟的NgZone
类,该类扩展了实际的NgZone
:
export class NgZoneMock extends NgZone {
constructor() {
super({ enableLongStackTrace: false });
}
public runOutsideAngular<T>(fn: (...args: Array<any>) => T) { return fn(); }
public run<T>(fn: (...args: Array<any>) => T, applyThis?: any, applyArgs?: Array<any> | undefined) { return fn(); }
public runTask<T>(fn: (...args: Array<any>) => T, applyThis?: any, applyArgs?: Array<any> | undefined) { return fn(); }
public runGuarded<T>(fn: (...args: Array<any>) => T, applyThis?: any, applyArgs?: Array<any> | undefined) { return fn(); }
public onUnstable = new EventEmitter<any>();
public onStable = new EventEmitter<any>();
public onMicrotaskEmpty = new EventEmitter<any>();
public onError = new EventEmitter<any>();
}
然后仅使用TestBed
配置中的类:
TestBed.configureTestingModule({
providers: [{
provide: NgZone,
useClass: NgZoneMock
}],
declarations: [MyComponent]
})
值得一提的是,还有其他方法可以做到这一点(并且通常可以模拟任何服务)。以下是一些示例Running jasmine tests for a component with NgZone dependency。创建一个Jasmine Spy对象非常有用,但是我个人更喜欢将模拟放置在DRY实际服务文件旁边的单独文件中。当然,您也可以将“间谍对象”放入模拟文件中。