鉴于以下代码,我尝试测试Angular2的ngOnChanges生命周期钩子:
import { it,inject,fdescribe,beforeEachProviders,} from '@angular/core/testing'; import {TestComponentBuilder} from '@angular/compiler/testing'; import {Component,OnChanges,Input} from '@angular/core'; @Component({ selector: 'test',template: `<p>{{value}}</p>`,}) export class TestComponent implements OnChanges { @Input() value: string; ngOnChanges(changes: {}): any { // should be called } } fdescribe('TestComponent',() => { let tcb: TestComponentBuilder; beforeEachProviders(() => [ TestComponentBuilder,TestComponent,]); beforeEach(inject([TestComponentBuilder],_tcb => { tcb = _tcb; })); it('should call ngOnChanges',done => { tcb.createAsync(TestComponent).then(fixture => { let testComponent: TestComponent = fixture.componentInstance; spyOn(testComponent,'ngOnChanges').and.callThrough(); testComponent.value = 'Test'; fixture.detectChanges(); expect(testComponent.ngOnChanges).toHaveBeenCalled(); done(); }).catch(e => done.fail(e)); }); });
不幸的是,测试失败,并且调用了Expected spy ngOnChanges消息.我知道我可以在这个例子中检查HTML元素的内容,但是我有一些代码需要在ngOnChanes生命周期钩子里面进行测试,所以这对我来说不是解决方案.我也不想调用testComponent.ngOnChanges({someMockData});在测试中直接.
如何从测试中设置TestComponent.value以便调用ngOnChanges?
猜猜我有点迟到了,不过这可能对将来有些人有用.
由于RC 5的角度已经释放,因此测试发生了一些变化.但是,这里的主要问题是在以编程方式设置输入时不会调用ngOnChanges. See this for more info基本上,只有通过视图传递输入时才会触发OnChanges挂钩.
解决方案是让主机组件成为测试组件的父组件,并通过主机组件的模板传递输入.
这是完整的工作代码:
import {Component,Input,ViewChild} from '@angular/core'; import { TestBed } from '@angular/core/testing'; @Component({ selector: 'test',}) export class TestComponent implements OnChanges { @Input() value: string; ngOnChanges(changes: {}): any { // should be called } } /* In the host component's template we will pass the inputs to the actual * component to test,that is TestComponent in this case */ @Component({ selector : `test-host-component`,template : `<div><test [value]="valueFromHost"></test></div>` }) export class TestHostComponent { @ViewChild(TestComponent) /* using viewChild we get access to the TestComponent which is a child of TestHostComponent */ public testComponent: any; public valueFromHost: string; /* this is the variable which is passed as input to the TestComponent */ } describe('TestComponent',() => { beforeEach(() => { TestBed.configureTestingModule({declarations: [TestComponent,TestHostComponent]}); /* We declare both the components as part of the testing module */ }); it('should call ngOnChanges',()=> { let fixture = TestBed.createComponent(TestHostComponent); let testHostComponent = fixture.componentInstance; testHostComponent.valueFromHost = 'Test'; spyOn(testHostComponent.testComponent,'ngOnChanges').and.callThrough(); fixture.detectChanges(); expect(testHostComponent.testComponent.ngOnChanges).toHaveBeenCalled(); }) });