Komponen anak uji unit sudut

Sep 19 2020

Saya menulis unit test untuk salah satu aplikasi Angular saya yang terdiri dari beberapa komponen. Di salah satu komponen saya (Komponen A), ia memiliki komponen anak seperti di bawah ini

Komponen 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>



Jika Anda melihat HTML di atas di KomponenA saya mengalami komponen yang memanggil fungsi ketika kolom diubah ukurannya di Grid yang akan memanggil onColumnResized () di dalam ComponentA saya seperti di bawah ini

onColumnResized() {
    const updatedColumns: ColumnWidth[] = [];
    this.columnApi.getColumnState().forEach((column) => {
      updatedColumns.push({ field: column.colId, width: column.width });
    });
    this.store.dispatch(new DevicesActions.UpdateColumnWidth(updatedColumns));
  }

Pertanyaan saya adalah bagaimana cara memata-matai onColumnResized () atau dapatkah saya memanggil fungsinya secara langsung seperti di bawah ini


    describe('ColumnResized', () => {
        it('call the onColumnResized', () => {
          expect(component.onColumnResized()).toHaveBeenCalled();
        });
      });

Saya ingin tahu apakah ini adalah pendekatan yang benar serta dapatkah saya menggunakan spyOn () daripada memanggil fungsi secara langsung

Jawaban

1 ShashankVivek Sep 20 2020 at 18:52

Nidhin, sebelum saya memberikan jawaban izinkan saya menjelaskan maksud pengujian unit untuk suatu komponen.

Pengujian unit komponen berarti Anda harus memeriksa perilaku (yang mencakup HTML & tskode) komponen. Satu faktor penting yang harus diingat adalah bahwa "kita harus mengisolasi komponen (yang sedang diuji) dari ketergantungan eksternal (kebanyakan layanan) sebanyak mungkin"

IMHO, Anda hanya perlu memeriksa apakah perilaku tersebut berfungsi saat onColumnResized()dipanggil. Anda tidak perlu khawatir apakah app-data-gridakan menelepon atau tidak (columnResized). Dalam app-data-gridpengujian, Anda harus menguji apakah columnResizeddinaikkan / dipanggil sesuai harapan.

Catatan: Anda harus menguji perilaku kedua komponen yang bekerja bersama sebagai bagian dari pengujian Integrasi , yang berarti Anda menguji kerja beberapa komponen secara bersamaan ( terintegrasi )

Dalam kasus Anda, untuk kode di bawah ini:

onColumnResized() {
    const updatedColumns: ColumnWidth[] = [];
    this.columnApi.getColumnState().forEach((column) => {
      updatedColumns.push({ field: column.colId, width: column.width });
    });
    this.store.dispatch(new DevicesActions.UpdateColumnWidth(updatedColumns));
 }

Anda harus melakukan tes di bawah ini:

  1. Jadikan storebagian dalam constructorsebagai publik (agar kita dapat memata-matai dengan mengaksesnya di luar komponen)
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 })
    );
  });
});

ATAU Anda dapat dengan mudah mengganti tipe pengembalian tanpa membuat 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 )
    );
  });
});

Anda dapat merujuk artikel saya ini di mana saya telah menggabungkan beberapa topik sebagai bagian dari tutorial pengujian Unit di Angular. Saya harap ini membantu.

1 Flavio Sep 19 2020 at 02:41

Anda sebaiknya tidak menguji apakah metode tersebut dipanggil. Anda harus menguji apakah komponen berperilaku benar saat komponen anak diubah ukurannya.

Ada pustaka yang bagus untuk mengejek komponen Anda: https://www.npmjs.com/package/ng-mocks

Sesuatu seperti itu:

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(...);
});

Dengan cara ini pengujian Anda tidak bergantung pada implementasi internal komponen Anda.

Anda perlu tahu apakah sebuah metode bernama onColumnResizeddipanggil. Anda harus memastikan, bahwa toko Anda diperbarui dengan kolom yang benar ketika terjadi perubahan ukuran ...