单元测试用例:期望从构造函数调用组件函数

Unit test case: expect a component function to have been called from a constructor

我有以下组件:

export class MyComponent {
   constructor() { this.getStorageData(); }
   getStorageData() {...}
}

我正在尝试测试以下情况:创建组件后,应该调用函数 getStorageData。这就是我尝试这样做的方式:

beforeEach(() => {
  fixture = TestBed.createComponent(MyComponent);
  component = fixture.componentInstance;
})

it('should create', async(()=> {
   var spy = spyOn(component, "getStorageData").and.callThrough();
   fixture.detectChanges();
   expect(component).toBeDefined();
   expect(component.getStorageData).toHaveBeenCalled();
}))

测试的最后一行总是测试失败。我做错了什么?

之所以没有被调用,是因为 spyOn 方法是在组件创建之后调用的,所以在构造函数被调用之后。有几种解决方法:

  1. 将函数调用移动到 ngOnInit 挂钩:
export class MyComponent {
  constructor() {}

  ngOnInit(): void {
    this.getStorageData();
  }

  getStorageData() {...}
}

您只需确保在第一个 detectChanges() 之前调用 spyOn。然后你就可以离开测试了


  1. 只需使用 new 初始化组件并将间谍添加到原型中:
it('should call getStorageData', function() {
  spyOn(MyComponent.prototype, 'getStorageData').and.callThrough();
  const component = new MyComponent();
  expect(MyComponent.prototype.getStorageData).toHaveBeenCalled();
});

您将自己提供任何可能的构造函数提供程序,因为依赖注入将不起作用


  1. 将间谍放在 beforeEach 原型上
beforeEach(() => {
  spyOn(MyComponent.prototype, 'getStorageData').and.callThrough();
  fixture = TestBed.createComponent(MyComponent);
  component = fixture.componentInstance;
})

it('should create', async(()=> {   
   fixture.detectChanges();
   expect(component).toBeDefined();
   expect(MyComponent.prototype.getStorageData).toHaveBeenCalled();
}))

您可能应该考虑隔离此测试,以确保它不会被本规范中的每个测试所监视。