【问题标题】:How to write unit jest test for Angular Component without TestBed?如何在没有 TestBed 的情况下为 Angular 组件编写单元笑话测试?
【发布时间】:2021-07-05 20:02:58
【问题描述】:

我对开玩笑测试很陌生,我很困惑为什么我的所有测试都失败了。

如果您知道任何视频或文章专门帮助编写没有“TestBed”的 Angular 组件、服务等的开玩笑单元测试,请告诉我。

这是我的代码:

voice-details-graph.component.ts

@Component({
  selector: 'senet-voice-details-graph',
  templateUrl: './voice-details-graph.component.html',
  styleUrls: ['./voice-details-graph.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class VoiceDetailsGraphComponent {
  vm$: Observable<IVoiceSummary> = this._voiceDetailsFacade.vm$.pipe(
    map(vm => vm.graphDetails)
  );

  constructor(private _voiceDetailsFacade: VoiceDetailsFacade) {}

  setCdrFilters() {
    this._voiceDetailsFacade.setCDRInitialOptions();
  }

  removeHyphen(phone: string) {
    return phone.replace(/-|\s/g, '');
  }
}

voice-details-graph.component.spec.ts

import { Injectable } from '@angular/core';
import { VoiceDetailsGraphComponent } from './voice-details-graph.component';

@Injectable()
class MockService {}

describe('VoiceDetailsGraphComponent', () => {
  let component: any;

  beforeEach(() => {
    component = new VoiceDetailsGraphComponent(new MockService() as any);
  });

  it('should run #constructor()', () => {
    expect(component).toBeTruthy();
  });

  it('should run #setCdrFilters()', async () => {
    component._voiceDetailsFacade.setCDRInitialOptions = jest.fn();
    component.setCdrFilters();
    expect(component._voiceDetailsFacade.setCDRInitialOptions).toHaveBeenCalled();
  });

  it('should run #removeHyphen()', async () => {
    const input = '1-800-999-9999';
    const output = '18009999999';
    component.phone.replace = jest.fn();
    expect(component.removeHyphen(input)).toEqual(output);
    expect(component.phone.replace.toHaveBeenCalled());
  });
});

失败:

 FAIL   senet-voice  libs/senet/voice/src/lib/features/voice-details/voice-details-graph/voice-details-graph.component.spec.ts (11.104 s)
  ● VoiceDetailsGraphComponent › should run #constructor()

    TypeError: Cannot read property 'pipe' of undefined

      13 | })
      14 | export class VoiceDetailsGraphComponent {
    > 15 |   vm$: Observable<IVoiceSummary> = this._voiceDetailsFacade.vm$.pipe(
         |                                                                 ^
      16 |     map(vm => vm.graphDetails)
      17 |   );
      18 | 

  ● VoiceDetailsGraphComponent › should run #constructor()

    expect(received).toBeTruthy()

    Received: undefined

      13 | 
      14 |   it('should run #constructor()', () => {
    > 15 |     expect(component).toBeTruthy();
         |                       ^
      16 |   });
      17 | 
      18 |   it('should run #setCdrFilters()', async () => {

  ● VoiceDetailsGraphComponent › should run #setCdrFilters()

    TypeError: Cannot read property 'pipe' of undefined

      13 | })
      14 | export class VoiceDetailsGraphComponent {
    > 15 |   vm$: Observable<IVoiceSummary> = this._voiceDetailsFacade.vm$.pipe(
         |                                                                 ^
      16 |     map(vm => vm.graphDetails)
      17 |   );
      18 | 

  ● VoiceDetailsGraphComponent › should run #setCdrFilters()

    TypeError: Cannot read property '_voiceDetailsFacade' of undefined

      17 | 
      18 |   it('should run #setCdrFilters()', async () => {
    > 19 |     component._voiceDetailsFacade.setCDRInitialOptions = jest.fn();
         |               ^
      20 |     component.setCdrFilters();
      21 |     expect(component._voiceDetailsFacade.setCDRInitialOptions).toHaveBeenCalled();
      22 |   });

  ● VoiceDetailsGraphComponent › should run #removeHyphen()

    TypeError: Cannot read property 'pipe' of undefined

      13 | })
      14 | export class VoiceDetailsGraphComponent {
    > 15 |   vm$: Observable<IVoiceSummary> = this._voiceDetailsFacade.vm$.pipe(
         |                                                                 ^
      16 |     map(vm => vm.graphDetails)
      17 |   );
      18 | 

  ● VoiceDetailsGraphComponent › should run #removeHyphen()

    TypeError: Cannot read property 'phone' of undefined

      25 |     const input = '1-800-999-9999';
      26 |     const output = '18009999999';
    > 27 |     component.phone.replace = jest.fn();
         |               ^
      28 |     expect(component.removeHyphen(input)).toEqual(output);
      29 |     expect(component.phone.replace.toHaveBeenCalled());
      30 |   });


【问题讨论】:

  • 如果您不熟悉测试,为什么您认为在没有测试平台的情况下进行测试是个好主意?实际上不是。您以这种方式使 DI 部分未经测试,并自行复制真实事物的工作方式。 vm$ 预计用于组件构造。你没有。
  • @PaulSamsotha 这是因为我们不关心这里的服务只测试组件。该服务有自己的规范文件。
  • @EstusFlask 在我工作的地方,我们不需要来自文档的 Testbed 引用:“注意:这里需要指出的是,Angular CLI 和第三方工具都使用来自 Angular 的 TestBed 模块生成规范文件。 . 如果我们要使用 HTML / UI 编写集成测试,这个模块很有用,但是由于集成测试是由 QA 团队编写的(参见“组件 HTML / UI 测试”部分),所以不需要这个模块,而是可以删除以支持更简单的方法。事实上,将此 TestBed 模块保留在您的测试文件中可以显着增加单元测试时间。"
  • 因为构造函数需要有 x 个参数 - 它只是模拟一个“参数”......如果我不这样做,那么我会收到一个 linter 错误。

标签: angular unit-testing jestjs


【解决方案1】:

这最终成为我的解决方案:

我需要在 beforeEach 函数中添加一个带有 vm$ observable obj 的模拟对象。

import { of } from 'rxjs';
import { VoiceDetailsGraphComponent } from './voice-details-graph.component';

describe('VoiceDetailsGraphComponent', () => {
  let component: any;

  beforeEach(() => {
    const mockFacade = {
      vm$: of({}),
    };
    component = new VoiceDetailsGraphComponent(mockFacade as any);
  });

  it('should run #constructor()', () => {
    expect(component).toBeTruthy();
  });

  it('should run #setCdrFilters()', async () => {
    component._voiceDetailsFacade.setCDRInitialOptions = jest.fn();
    component.setCdrFilters();
    expect(
      component._voiceDetailsFacade.setCDRInitialOptions
    ).toHaveBeenCalled();
  });

  it('should run #removeHyphen()', async () => {
    const input = '1-800-999-9999';
    const output = '18009999999';
    expect(component.removeHyphen(input)).toEqual(output);
  });
});

【讨论】:

    猜你喜欢
    • 2020-05-09
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 2023-01-09
    • 2021-01-27
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多