Angular 我如何用单元测试涵盖rxjs订阅方法?

Angular 我如何用单元测试涵盖rxjs订阅方法?,angular,rxjs,angular-unit-test,Angular,Rxjs,Angular Unit Test,我试图编写单元测试来覆盖我的每一行代码。我有两行代码没有涵盖 我不明白我在哪里犯了错误,以及我如何才能覆盖这些代码行 以下是未覆盖代码行的图像: Product-item.spect.ts 从'@angular/common/http/testing'导入{HttpClientTestingModule}; 从“@angular/core”导入{CUSTOM_ELEMENTS_SCHEMA}”; 从“@angular/core/testing”导入{async,ComponentFixture

我试图编写单元测试来覆盖我的每一行代码。我有两行代码没有涵盖

我不明白我在哪里犯了错误,以及我如何才能覆盖这些代码行

以下是未覆盖代码行的图像:

Product-item.spect.ts

从'@angular/common/http/testing'导入{HttpClientTestingModule};
从“@angular/core”导入{CUSTOM_ELEMENTS_SCHEMA}”;
从“@angular/core/testing”导入{async,ComponentFixture,TestBed};
从“@angular/router/testing”导入{RouterTestingModule};
从“../../services/product.service”导入{ProductService};
从“./product item.component”导入{ProdItemComponent};
描述('ProdItemComponent',()=>{
let组件:ProdItemComponent;
let夹具:组件夹具;
让产品服务:产品服务;
让我们来看看这个项目:任何;
beforeach(异步(()=>{
TestBed.configureTestingModule({
声明:[ProductItemComponent],
导入:[HttpClientTestingModule,RouterTestingModule],
提供者:[ProductService],
模式:[自定义元素\u模式]
})
.compileComponents();
}));
在每个之前(()=>{
mockProductItem={
id:“c7336f01-5219-4631-a865-af1fa9837766”,
标题:“地毯”,
描述:“柔软的地毯”
}
fixture=TestBed.createComponent(ProductItemComponent);
组件=fixture.componentInstance;
productService=TestBed.inject(productService);
fixture.detectChanges();
component.productItem=mockProductItem;
component.selectedItemId=component.mockProductItem.id;
});
它('应该创建',()=>{
expect(component.toBeTruthy();
});
它('应该调用delete方法',()=>{
component.onDelete();
fixture.detectChanges();
productService.deleteProduct(component.selectedItemId).subscribe(selectedItemId=>{
expect(selectedItemId.toBeTruthy();
const spy=spyOn(component.fetchDataEventEmitter,'emit');
期望(间谍)。已被调用();
})
});
expect(component.displayConfirmDialog).toBe(false);
});
产品服务

deleteProduct(productId:string){
返回this.httpClient.delete(
此.BASE\u URL+
这是一个.DELETE\u项目\u URL(
产品ID
)
)
}
产品组件

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

看起来您在执行过程中创建间谍对象的时间太晚了。如果您在调用productService.delete之前创建了spy对象,但将expect断言保留在原来的位置,则应该可以解决此问题。

尝试为
fetchDataEventEmitter
属性分配一个简单的可观察对象,并将其移到案例顶部:

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

最后一个
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();
  });

let组件:ProdItemComponent;
let夹具:组件夹具;
让产品服务:产品服务;
让我们来看看这个项目:任何;
//添加这一行
让mockProductService:jasmine.SpyObj;
beforeach(异步(()=>{
//创建一个间谍对象
//第一个字符串是标识符,是可选的
//是您想要嘲笑的公共方法。
mockProductService=jasmine.createSpyObj('ProductService',['deleteProduct']);
TestBed.configureTestingModule({
声明:[ProductItemComponent],
//摆脱HttpClientTestingModule,因为我们正在模拟
//立即提供产品服务
导入:[/*HttpClientTestingModule*/,RouterTestingModule],
//当组件请求ProductService时,给出模拟的一个
提供程序:[{提供:ProductService,useValue:mockProductService}],
模式:[自定义元素\u模式]
})
.compileComponents();
}));
...
它('应该调用delete方法',()=>{
//使deleteProduct方法返回一个可观察的空字符串
mockProductService.deleteProduct.and.returnValue(of(“”));
//监视发射
const emitSpy=spyOn(component.fetchDataEventEmitter,'emit');
component.onDelete();
fixture.detectChanges();
expect(emitSpy).tohavebeincall();
expect(component.displayConfirmDialog.toBeFalse();
});

我将这个“const spy=spyOn(component.fetchDataEventEmitter,'emit')移到了顶部,但是这些代码行是相同的,它仍然没有被覆盖。SPEC没有期望应该调用delete Method我在尝试为fetchDataEventEmitter分配一个简单的可观察对象时遇到了这个错误类型“Observable”缺少类型“EventEmitter”中的以下属性:emit、observators、closed、isStopped和其他7个属性。Doest
spyOn(component.fetchDataEventEmitter,“emit”)不行?好像不行。谢谢。现在,我将传递一行未包含的代码。