尽管投票率最高的答案有效,但它们并没有展示出良好的测试实践,所以我想我会在 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!');
}
}
组件是被测系统,监视它的某些部分会破坏封装。 Angular 组件测试应该只知道三件事:
- DOM(通过例如
fixture.nativeElement.querySelector 访问);
-
@Inputs 和 @Outputs 的名称;和
- 协作服务(通过 DI 系统注入)。
任何涉及在实例上直接调用方法或监视组件的某些部分的事情都与实现的耦合过于紧密,并且会增加重构的摩擦 - 测试替身应该只用于协作者。在这种情况下,由于我们没有合作者,我们不应该需要任何模拟、间谍或其他测试替身。
一种测试方法是直接订阅发射器,然后调用点击动作(参见Component with inputs and outputs):
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 inside a test host)并实际安装您的组件:
@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 是测试主机,因此我们可以确信我们没有过度耦合到我们实际测试的组件。