鉴于以下代码,我尝试测试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 to have been called.
我知道我可以在这个例子中检查HTML元素的内容,但是我有一些代码需要在ngOnChanes生命周期钩子里面进行测试,所以这不是我的解决方案。我也不想直接在测试中致电testComponent.ngOnChanges({someMockData});
。
如何从测试中设置TestComponent.value
以便调用ngOnChanges
?
答案 0 :(得分:43)
猜猜我有点迟到了,但是这可能对将来有些人有用。
由于RC 5的角度已经释放,因此测试发生了一些变化。但是,当以编程方式设置输入时,此处的主要问题是ngOnChanges
未被调用。 See this for more info。基本上,当仅通过视图传递输入>时,会触发OnChanges
挂钩。
解决方法是让主机组件成为测试组件的父组件,并通过主机组件的模板传递输入。
以下是完整的工作代码:
import {Component, OnChanges, Input, ViewChild} from '@angular/core';
import { TestBed } from '@angular/core/testing';
@Component({
selector: 'test',
template: `<p>{{value}}</p>`,
})
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();
})
});
答案 1 :(得分:11)
您还可以选择手动调用ngOnChanges挂钩并在那里传递所需的更改对象。但是这并没有设置组件属性,只调用更改逻辑。
PreparedStatement preparedStatement =
connection.prepareStatement("INSERT into table (tab1, tab2) VALUES(?, ?)");
preparedStatement.setString(1, bb);
preparedStatement.setString(2, bb1);
答案 2 :(得分:6)
在Angular 4中,要在测试时手动触发ngOnChanges()
,您必须手动拨打电话(如上所述),只需要匹配new call signature of SimpleChange():
let prev_value = "old";
let new_value = "new";
let is_first_change: boolean = false;
component.ngOnChanges({prop1: new SimpleChange(prev_value, new_value, is_first_change});