Sebbene le risposte con il voto più alto funzionino, non stanno dimostrando buone pratiche di test, quindi ho pensato di espandere la risposta di Günter con alcuni esempi pratici.
Immaginiamo di avere il seguente semplice componente:
@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!');
}
}
Il componente è il sistema sotto test, spiarne parti rompe l'incapsulamento. I test dei componenti angolari dovrebbero conoscere solo tre cose:
- Il DOM (accessibile tramite ad es.
fixture.nativeElement.querySelector
);
- Nomi dei
@Input
s e @Output
s; e
- Servizi di collaborazione (iniettati tramite il sistema DI).
Tutto ciò che implica l'invocazione diretta di metodi sull'istanza o lo spionaggio di parti del componente è troppo strettamente associato all'implementazione e aggiungerà attrito al refactoring: i doppi di test dovrebbero essere usati solo per i collaboratori. In questo caso, come non abbiamo collaboratori, non dovremmo avere bisogno di alcun prende in giro, spie o altri test raddoppia.
Un modo per verificarlo è iscriversi direttamente all'emettitore, quindi richiamare l'azione di clic (vedere Componente con ingressi e uscite ):
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!');
});
});
Sebbene questo interagisca direttamente con l'istanza del componente, il nome di @Output
fa parte dell'API pubblica, quindi non è troppo strettamente accoppiato.
In alternativa, puoi creare un semplice host di test (vedi Componente all'interno di un host di prova ) e montare effettivamente il tuo componente:
@Component({
selector: 'test-host',
template: `
<my-demo (clicked)="onClicked($event)"></my-demo>
`
})
class TestHostComponent {
lastClick = '';
onClicked(value: string): void {
this.lastClick = value;
}
}
quindi prova il componente nel contesto:
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!');
});
});
Il componentInstance
qui è l' ospite di prova , in modo che possiamo essere sicuri che non stiamo eccessivamente accoppiato alla componente in realtà stiamo testando.