Embora as respostas com maior votação funcionem, elas não estão demonstrando boas práticas de teste, então pensei em expandir a resposta de Günter com alguns exemplos práticos.
Vamos imaginar que temos o seguinte componente simples:
@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!');
}
}
O componente é o sistema em teste, espionando partes dele quebras de encapsulamento. Os testes de componentes angulares devem saber apenas sobre três coisas:
- O DOM (acessado via, por exemplo,
fixture.nativeElement.querySelector );
- Nomes de
@Inputs e@Output s; e
- Serviços de colaboração (injetados via sistema DI).
Qualquer coisa que envolva invocar métodos diretamente na instância ou espionar partes do componente está muito intimamente ligada à implementação e adicionará atrito à refatoração - duplas de teste devem ser usadas apenas para os colaboradores. Neste caso, como não temos colaboradores, devemos não precisa de nenhum simulações, espiões ou outras duplas de teste.
Uma maneira de testar isso é inscrevendo-se diretamente no emissor e, em seguida, invocando a ação de clique (consulte Componente com entradas e saídas ):
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!');
});
});
Embora isso interaja diretamente com a instância do componente, o nome do @Output faz parte da API pública, portanto, não é muito acoplado.
Como alternativa, você pode criar um host de teste simples (consulte Componente dentro de um host de teste ) e realmente montar seu componente:
@Component({
selector: 'test-host',
template: `
<my-demo (clicked)="onClicked($event)"></my-demo>
`
})
class TestHostComponent {
lastClick = '';
onClicked(value: string): void {
this.lastClick = value;
}
}
em seguida, teste o componente no contexto:
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!');
});
});
A componentInstanceaqui é o anfitrião de teste , para que possamos ter a certeza de que não estamos excessivamente acoplado ao componente estamos testando realmente.