Componente hijo de prueba de unidad angular
Estoy escribiendo una prueba unitaria para una de mis aplicaciones Angular que consta de varios componentes. En uno de mis componentes (Componente A), tiene un componente secundario como el siguiente
Componente A
<div class="row row-top">
<div class="col-12">
<app-data-grid
[columnDefs]="columnDefs"
[defaultColDef]="defaultColumnDefs"
[overlayNoRowsTemplate]="overlayNoRowsTemplate"
[hasFloatingFilter]="hasFloatingFilter"
[frameworkComponents]="frameworkComponents"
[rowData]="rowData"
[hasMultipleRows]="rowSelection"
[hasRowAnimation]="hasRowAnimation"
[multiSortKey]="multiSortKey"
(rowDataChanged)="onRowDataChanged()"
(selectionChanged)="onSelectionChanged()"
(rowClicked)="gotoDetailView($event)" (sortChanged)="onSortChanged($event)"
(columnResized)="onColumnResized()"
(gridReady)="OnGridReady($event)"
>
</app-data-grid>
<div class="float-right">
<button
id="addDevice"
type="button"
class="btn btn-brand btn-primary position-relative add-button"
(click)="gotoAddDevice()"
>
<i class="fa fa-plus"></i>
</button>
</div>
</div>
</div>
Si ve el HTML anterior en el ComponentA, tengo el componente que llama a las funciones cuando se cambia el tamaño de la columna en la cuadrícula que llamaría a onColumnResized () dentro de mi ComponentA como a continuación
onColumnResized() {
const updatedColumns: ColumnWidth[] = [];
this.columnApi.getColumnState().forEach((column) => {
updatedColumns.push({ field: column.colId, width: column.width });
});
this.store.dispatch(new DevicesActions.UpdateColumnWidth(updatedColumns));
}
Mi pregunta es cómo puedo espiar el onColumnResized () o puedo llamar a la función directamente como se muestra a continuación
describe('ColumnResized', () => {
it('call the onColumnResized', () => {
expect(component.onColumnResized()).toHaveBeenCalled();
});
});
Me gustaría saber si este es el enfoque correcto y si puedo usar spyOn () en lugar de llamar a la función directamente
Respuestas
Nidhin, antes de dar una respuesta, permítame explicar la intención de las pruebas unitarias para un componente.
La prueba unitaria de un componente significa que debe verificar el comportamiento (que incluye HTML y
tscódigo) de un componente. Un factor importante que debe tenerse en cuenta es que "debemos aislar el componente (que se está probando) de las dependencias externas (principalmente servicios) tanto como sea posible".
En mi humilde opinión, solo debe verificar si el comportamiento está funcionando cuando onColumnResized()se llama. No debe preocuparse si lo app-data-gridestá llamando o no (columnResized). En las app-data-gridpruebas, debe probar si columnResizedse genera / invoca según la expectativa.
Nota: debe probar el comportamiento de ambos componentes trabajando juntos como parte de la prueba de integración , lo que significa que prueba el funcionamiento de varios componentes juntos ( integrados )
En su caso, para el siguiente código:
onColumnResized() {
const updatedColumns: ColumnWidth[] = [];
this.columnApi.getColumnState().forEach((column) => {
updatedColumns.push({ field: column.colId, width: column.width });
});
this.store.dispatch(new DevicesActions.UpdateColumnWidth(updatedColumns));
}
debe hacer las siguientes pruebas:
- Hacer
storedentro delconstructorcomo público (para que podamos espiarlo accediendo fuera del componente)
export class MockColumnApi {
getColumnState() {
return [
{colId: 1, column: 2 }
];
}
}
describe('SomeComponent', () => {
let component: SomeComponent;
let fixture: ComponentFixture<SomeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
// whatever you need to import
],
declarations: [SomeComponent, GridComponent],
providers: [
{ provide: ColumnApi, useClass: MockColumnApi },
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should create dispatch columns on resize call', () => {
spyOn(component.columnApi, 'getColumnState').and.callThrough();
spyOn(component.store, 'dispatch').and.callThrough();
component.onColumnResized();
expect(component.columnApi.getColumnState).toHaveBeenCalled()
expect(component.store.dispatch).toHaveBeenCalledWith(
new DevicesActions.UpdateColumnWidth({colId: 1, column: 2 })
);
});
});
O simplemente puede anular el tipo de retorno sin crear un MockColumnApi:
describe('SomeComponent', () => {
let component: SomeComponent;
let fixture: ComponentFixture<SomeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
// whatever you need to import
],
declarations: [SomeComponent, GridComponent],
providers: [
{ provide: ColumnApi, useClass: MockColumnApi },
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should create dispatch columns on resize call', () => {
const sampleData = [
{colId: 1, column: 2 }
];
spyOn(component.columnApi, 'getColumnState').and.returnValue(sampleData );
spyOn(component.store, 'dispatch').and.callThrough();
component.onColumnResized();
expect(component.columnApi.getColumnState).toHaveBeenCalled()
expect(component.store.dispatch).toHaveBeenCalledWith(
new DevicesActions.UpdateColumnWidth(sampleData )
);
});
});
Puede consultar este artículo mío donde he combinado algunos temas como parte del tutorial de pruebas unitarias en Angular. Espero que te ayude.
No debe probar si se llama al método. Debe probar si el componente se comporta correctamente cuando se cambia el tamaño del componente secundario.
Hay una buena biblioteca para burlarse de sus componentes: https://www.npmjs.com/package/ng-mocks
Algo como eso:
let columnApiMock: jasmine.SpyObj<ColumnApi>;
beforeEach(() => {
TestBed.configureTestingModule({
...
providers: [
{ provide: YourStoreService,
useValue: jasmine.createSpyObj('YourStoreService', ['dispatch']) },
{ provide: ColumnApi,
useValue: jasmine.createSpyObj('ColumnApi', ['getColumnState']) },
],
declarations: [
AppComponentA, // not mocked
MockComponent(AppDataGrid),
],
});
columnApiMock = TestBed.inject(ColumnApi) as jasmine.SpyObj<ColumnApi>;
})
...
it('test if columns are stored on resize', () => {
// expect you have mocked your colum api, prepare columns that should be returned
columnApiMock.getColumnState.and.returnValue([...]);
const dataGridMock = ngMocks.find(fixture.debugElement, AppDataGrid);
// trigger Output from DataGrid
dataGridMock.columnResized.emit();
expect(TestBed.inject(YourStoreService).dispatch))
.toHaveBeenCalledWith(...);
});
De esta manera, sus pruebas no dependen de la implementación interna de su componente.
Necesita saber si onColumnResizedse llama a un método llamado. Debe asegurarse de que su tienda se actualice con las columnas correctas cuando se produzca un cambio de tamaño ...