簡體   English   中英

如何使用單元測試涵蓋 rxjs 訂閱方法?

[英]How can I cover rxjs subscribe method with unit tests?

我正在嘗試編寫單元測試來覆蓋我的每一行代碼。 我有兩行代碼沒有被覆蓋。

我不明白我在哪里犯了錯誤以及如何覆蓋這些代碼行?

這是未覆蓋的代碼行的圖像:

代碼覆蓋率截圖

產品-item.spect.ts

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture,TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ProductService } from '../../services/product.service';
import { ProdItemComponent } from './product-item.component';

describe('ProdItemComponent', () => {
  let component: ProdItemComponent;
  let fixture: ComponentFixture<ProdItemComponent>;
  let productService: ProductService;
  let mockProductItem: any;

  beforeEach(async(() => {

    TestBed.configureTestingModule({
      declarations: [ProductItemComponent],
      imports: [HttpClientTestingModule, RouterTestingModule],
      providers: [ProductService],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    })
      .compileComponents();
  }));

  beforeEach(() => {

    mockProductItem= {
      id: "c7336f01-5219-4631-a865-af1fa9837766",
      title:"Carpet",
      description:"A soft Carpet"
    }

    fixture = TestBed.createComponent(ProductItemComponent);
    component = fixture.componentInstance;
    productService = TestBed.inject(ProductService);
    fixture.detectChanges();
    component.productItem = mockProductItem;
    component.selectedItemId = component.mockProductItem.id;

  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should call delete method', () => {
    component.onDelete();
    fixture.detectChanges();
    productService.deleteProduct(component.selectedItemId).subscribe(selectedItemId => {
      expect(selectedItemId).toBeTruthy();
      const spy = spyOn(component.fetchDataEventEmitter, 'emit');
      expect(spy).toHaveBeenCalled();
    })
  });
  expect(component.displayConfirmDialog).toBe(false);
});

產品服務.ts

 deleteProduct(productId: string) {
    return this.httpClient.delete(
      this.BASE_URL +
      this.DELETE_ITEM_URL(
        productId
      )
    )
  }

產品組件.ts

onDelete(): void {
    if (this.selectedItemId) {
      this.productService.deleteProduct(this.selectedItemId).subscribe(res => {
        this.fetchDataEventEmitter.emit();
      });
    }
    this.displayConfirmDialog = false;
  }

這里的最后一個expect是不合適的,它應該移動一行。

  it('should call delete method', () => {
    component.onDelete();
    fixture.detectChanges();
    productService.deleteProduct(component.selectedItemId).subscribe(selectedItemId => {
      expect(selectedItemId).toBeTruthy();
      const spy = spyOn(component.fetchDataEventEmitter, 'emit');
      expect(spy).toHaveBeenCalled();
    });
    // should go here
    expect(component.displayConfirmDialog).toBe(false);
  });
  // expect(component.displayConfirmDialog).toBe(false);

您需要使用 spyObject 模擬ProductService ,因為您不想在單元測試中進行實際的http調用。

  let component: ProdItemComponent;
  let fixture: ComponentFixture<ProdItemComponent>;
  let productService: ProductService;
  let mockProductItem: any;
  // add this line
  let mockProductService: jasmine.SpyObj<ProductService>;

  beforeEach(async(() => {
    // create a spy object
    // the first string is an identifier and is optional. The array of strings
    // are the public methods that you would like to mock.
    mockProductService = jasmine.createSpyObj<ProductService>('ProductService', ['deleteProduct']);
    TestBed.configureTestingModule({
      declarations: [ProductItemComponent],
      // get rid of HttpClientTestingModule since we are mocking
      // ProductService now
      imports: [/*HttpClientTestingModule*/, RouterTestingModule],
      // when the component asks for ProductService, give the mocked one
      providers: [{ provide: ProductService, useValue: mockProductService }],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    })
      .compileComponents();
  }));

...
it('should call delete method', () => {
    // make the deleteProduct method return an observable of empty string
    mockProductService.deleteProduct.and.returnValue(of(''));
    // spy on the emission
    const emitSpy = spyOn(component.fetchDataEventEmitter, 'emit');

    component.onDelete();
    fixture.detectChanges();

    expect(emitSpy).toHaveBeenCalled();
    expect(component.displayConfirmDialog).toBeFalse();
  });

看起來您在執行過程中創建間諜 object 為時已晚。 如果您在調用 productService.delete 之前創建了間諜 object 但將期望斷言保留在原處,那應該可以解決問題。

嘗試為您的fetchDataEventEmitter屬性分配一個簡單的 observable 並將其移動到案例的頂部:

 it('should call delete method', () => {
    component.fetchDataEventEmitter = of({})
    component.onDelete();
    fixture.detectChanges();
    productService.deleteProduct(component.selectedItemId).subscribe(selectedItemId => {
      expect(selectedItemId).toBeTruthy();
    })
  });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM