[英]Angular unit test child component
我正在为我的一个由多个组件组成的 Angular 应用程序编写单元测试。 在我的一个组件(组件 A)中,它有一个如下所示的子组件
组分 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>
如果你在 ComponentA 中看到上面的 HTML,我有当列在 Grid 中调整大小时调用函数的组件,它将调用我的 ComponentA 中的 onColumnResized(),如下所示
onColumnResized() {
const updatedColumns: ColumnWidth[] = [];
this.columnApi.getColumnState().forEach((column) => {
updatedColumns.push({ field: column.colId, width: column.width });
});
this.store.dispatch(new DevicesActions.UpdateColumnWidth(updatedColumns));
}
我的问题是我如何监视onColumnResized()或者我可以像下面一样直接调用该函数
describe('ColumnResized', () => {
it('call the onColumnResized', () => {
expect(component.onColumnResized()).toHaveBeenCalled();
});
});
我想知道这是否是正确的方法以及我可以使用 spyOn() 而不是直接调用函数
您不应该测试该方法是否被调用。 您应该测试在调整子组件大小时组件的行为是否正确。
有一个很好的库来模拟你的组件: https : //www.npmjs.com/package/ng-mocks
类似的东西:
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(...);
});
这样您的测试就不会依赖于组件的内部实现。
您需要知道是否调用了名为onColumnResized
的方法。 您必须确保在调整大小时使用正确的列更新您的商店......
Nidhin,在我提供一些答案之前,让我解释一下对组件进行单元测试的意图。
组件的单元测试意味着您应该检查组件的行为(包括 HTML 和
ts
代码)。 应该记住的一个重要因素是“我们应该尽可能地将组件(正在测试的)与外部依赖项(主要是服务)隔离开来”
恕我直言,您应该只在onColumnResized()
时检查行为是否有效。 您不应该担心app-data-grid
是否在(columnResized)
上调用它。 在app-data-grid
测试中,您应该测试是否按照预期引发/调用columnResized
。
注意:作为集成测试的一部分,您应该测试两个组件一起工作的行为,这意味着您一起测试多个组件的工作(集成)
在您的情况下,对于以下代码:
onColumnResized() {
const updatedColumns: ColumnWidth[] = [];
this.columnApi.getColumnState().forEach((column) => {
updatedColumns.push({ field: column.colId, width: column.width });
});
this.store.dispatch(new DevicesActions.UpdateColumnWidth(updatedColumns));
}
你应该做以下测试:
constructor
内部的store
设为 public(以便我们可以通过在组件外部访问它来监视它)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 })
);
});
});
或者您可以简单地覆盖返回类型而不创建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 )
);
});
});
您可以参考我的这篇文章,其中我结合了几个主题作为 Angular 单元测试教程的一部分。 我希望它有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.