我有一个使用 EventEmitter 的组件,当单击页面上的某个人时,将使用 EventEmitter。有没有什么方法可以让我在单元测试期间观察 EventEmitter,然后使用 TestComponent Builder 单击触发 EventEmitter.next ()方法的元素,看看发送了什么?
您可以在父模板中订阅发射器或绑定到它(如果它是 @Output()) ,并在绑定更新时检入父组件。 您还可以分派一个单击事件,然后订阅应该触发。
@Output()
你的测试可能是:
it('should emit on click', () => { const fixture = TestBed.createComponent(MyComponent); // spy on event emitter const component = fixture.componentInstance; spyOn(component.myEventEmitter, 'emit'); // trigger the click const nativeElement = fixture.nativeElement; const button = nativeElement.querySelector('button'); button.dispatchEvent(new Event('click')); fixture.detectChanges(); expect(component.myEventEmitter.emit).toHaveBeenCalledWith('hello'); });
当你的组件是:
@Component({ ... }) class MyComponent { @Output myEventEmitter = new EventEmitter<string>(); buttonClick() { this.myEventEmitter.emit('hello'); } }
你可以用间谍,这取决于你的风格。以下是如何轻松使用间谍,看看是否 emit正在开火..。
emit
it('should emit on click', () => { spyOn(component.eventEmitter, 'emit'); component.buttonClick(); expect(component.eventEmitter.emit).toHaveBeenCalled(); expect(component.eventEmitter.emit).toHaveBeenCalledWith('bar'); });
我需要测试发出的数组的长度。这就是我如何在其他答案的基础上做到这一点。
expect(component.myEmitter.emit).toHaveBeenCalledWith([anything(), anything()]);
虽然得票最高的答案起作用了,但它们并没有展示出良好的测试实践,所以我想用一些实际的例子来扩展 Günter's answer。
假设我们有下面这个简单的组件:
@Component({ selector: 'my-demo', template: ` <button (click)="buttonClicked()">Click Me!</button> ` }) export class DemoComponent { @Output() clicked = new EventEmitter<string>(); constructor() { } buttonClicked(): void { this.clicked.emit('clicked!'); } }
该组件就是正在测试的系统,监视它的部分内容会破坏封装。角度分量测试只应该知道三件事:
fixture.nativeElement.querySelector
@Input
@Output
任何涉及到直接调用实例方法或监视组件部分内容的内容都与实现过于紧密地耦合在一起,并且会给重构增加阻力——测试替身应该只用于协作者。在这种情况下,由于我们没有合作者,我们不应该需要 任何模拟,间谍或其他测试替身。
一种测试方法是直接订阅发射器,然后调用 click 操作(参见 具有输入和输出的组件) :
describe('DemoComponent', () => { let component: DemoComponent; let fixture: ComponentFixture<DemoComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ DemoComponent ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(DemoComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should emit when clicked', () => { let emitted: string; component.clicked.subscribe((event: string) => { emitted = event; }); fixture.nativeElement.querySelector('button').click(); expect(emitted).toBe('clicked!'); }); });
虽然这直接与组件实例交互,但是 @Output的名称是公共 API 的一部分,所以它不会耦合得太紧。
或者,您可以创建一个简单的测试主机(参见 测试主机中的组件)并实际挂载您的组件:
@Component({ selector: 'test-host', template: ` <my-demo (clicked)="onClicked($event)"></my-demo> ` }) class TestHostComponent { lastClick = ''; onClicked(value: string): void { this.lastClick = value; } }
然后在上下文中测试组件:
describe('DemoComponent', () => { let component: TestHostComponent; let fixture: ComponentFixture<TestHostComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ TestHostComponent, DemoComponent ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(TestHostComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should emit when clicked', () => { fixture.nativeElement.querySelector('button').click(); expect(component.lastClick).toBe('clicked!'); }); });
这里的 componentInstance是 测试主机,所以我们可以确信我们没有过度耦合到我们实际测试的组件。
componentInstance
测试:@Output ()值 new EventEmitter () ;
超文本标示语言
<input [(ngModel)]="_myInputValue" class="my-input" (keyup)="value.emit($event.target.value)" />
规格
it('should emit a value when user types input', () => { spyOn(component.value, 'emit'); element.query(By.css('.my-input')) .triggerEventHandler('keyup', {target: {value: 'my input value'}}); fixture.detectChanges(); expect(component.value.emit).toHaveBeenCalled(); expect(component.value.emit).toHaveBeenCalledWith('my input value'); }
注意: triggerEventHandler ()