Angular 测试:Mock 未按预期运行

Angular testing: Mock is not functioning as expected

我正在尝试为我的组件编写单元测试,但似乎无法让它工作。我的组件如下所示:

import { Component, OnInit } from '@angular/core';
import {ModalController} from '@ionic/angular';
import {CheckInsProvider} from '../../providers/check-ins.service';
import * as _ from 'lodash'
import {WeighInsProvider} from '../../pages/clients/client-detail/providers/weigh-ins/weigh-ins.service';

@Component({
  selector: 'app-re-evaluation',
  templateUrl: './re-evaluation.component.html',
  styleUrls: ['./re-evaluation.component.scss'],
})
export class ReEvaluationComponent implements OnInit {
  programId: number;
  initialWeight: number;
  endingWeight: number;
  initialBodyFat: number;
  endingBodyFat: number;
  initialVisceralFat: number;
  endingVisceralFat: number;

  constructor( private modalCtrl: ModalController,
               private checkInsProvider: CheckInsProvider,
               private weighInsProvider: WeighInsProvider ) { }

  ngOnInit() {
    this.fetchWeights()
  }

  fetchWeights() {
    console.log("here", this.weighInsProvider.findFirstWithField('current_weight'))
    this.initialWeight = this.weighInsProvider.findFirstWithField('current_weight').current_weight
    this.endingWeight = this.weighInsProvider.findLastWithField('current_weight').current_weight

    this.initialBodyFat = this.weighInsProvider.findFirstWithField('body_fat').body_fat
    this.endingBodyFat = this.weighInsProvider.findLastWithField('body_fat').body_fat

    this.initialVisceralFat = this.weighInsProvider.findFirstWithField('visceral_fat').visceral_fat
    this.endingVisceralFat = this.weighInsProvider.findLastWithField('visceral_fat').visceral_fat
  }

  dismiss(): void {
    this.modalCtrl.dismiss()
  }
}

我的测试是这样的:

describe('ReEvaluationComponent', () => {
  let component: ReEvaluationComponent;
  let fixture: ComponentFixture<ReEvaluationComponent>;
  let mockGlobalsService = jasmine.createSpyObj('GlobalsService', ['base_url'])
  let checkInsService: any;
  let weighInsService: any;
  let injector: TestBed;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ ReEvaluationComponent ],
      imports: [
        IonicModule.forRoot(),
        HttpClientTestingModule,
        RouterTestingModule,
      ],
      providers: [
        WeighInsProvider,
        {provide: GlobalsService, useValue: mockGlobalsService},
        {provide: PurchasesService, useValue: PurchasesServiceMock},
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(ReEvaluationComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

  beforeEach(() => {
    injector = getTestBed()
    checkInsService = injector.get(CheckInsProvider)
    weighInsService = injector.get(WeighInsProvider)
  })

  it('should create', () => {
    spyOn(weighInsService, 'findFirstWithField').and.returnValue({
        current_weight: 200,
        visceral_fat: 20,
        body_fat: 20
      })
    expect(component).toBeTruthy();
  });

  ...

并且 should create 测试失败,说明:

ReEvaluationComponent should create FAILED
Failed: Cannot read properties of undefined (reading 'current_weight')

这对我来说很奇怪,因为我认为我的间谍会 return 价值:

{
    current_weight: 200,
    visceral_fat: 20,
    body_fat: 20
}

我做错了什么?

我认为问题在于,您创建间谍为时已晚。您正在组件的 ngOnInit 中使用 current_weight

您的组件已创建(并将 运行 ngOnInit)在您的第一个测试之前,您将在其中执行 spyOn.

尝试按如下方式重构您的测试:

describe('ReEvaluationComponent', () => {
    let component: ReEvaluationComponent;
    let fixture: ComponentFixture<ReEvaluationComponent>;
    let mockGlobalsService = jasmine.createSpyObj('GlobalsService', ['base_url'])
    let checkInsService: any;
    let weighInsService: any;
    let injector: TestBed;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
        declarations: [ ReEvaluationComponent ],
        imports: [
            IonicModule.forRoot(),
            HttpClientTestingModule,
            RouterTestingModule,
        ],
        providers: [
            WeighInsProvider,
            {provide: GlobalsService, useValue: mockGlobalsService},
            {provide: PurchasesService, useValue: PurchasesServiceMock},
        ]
        }).compileComponents();
    }));

    beforeEach(() => {
        injector = getTestBed()
        checkInsService = injector.get(CheckInsProvider)
        weighInsService = injector.get(WeighInsProvider)

        spyOn(weighInsService, 'findFirstWithField').and.returnValue({
            current_weight: 200,
            visceral_fat: 20,
            body_fat: 20
        });

        spyOn(weighInsService, 'findLastWithField').and.returnValue({
            current_weight: 200,
            visceral_fat: 20,
            body_fat: 20
        });
    });

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

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

...

这将允许您首先为您的服务设置模拟,然后才创建一个使用模拟服务的组件。