错误:<toHaveBeenCalled>:期望有间谍,但在Jamsine中得到了Function

时间:2020-05-31 18:01:12

标签: angular unit-testing karma-jasmine

我是使用Jasmine和Karma在Angular中进行单元测试的新手。我已经写了一个规格文件,但出现错误。首先让我展示一下我到目前为止所做的事情。我创建了一个自定义组件:

TimeselectorComponent

startRange = moment('12-01-01');
endRange = moment ('12-12-01');

modes= ['Calendar Year', 'Year-to-date', 'Rolling Year', 'Custom'];

date = new Date();
currentYear = this.date.getFullYear(); // or simply currentYear = 2020;

@ViewChild('primaryMonthPicker') primaryMonthPicker: MonthpickerComponent; // a child component

primaryDropDown(startRange, endRange) {
    if (this.primaryMode === this.modes[0]) {
        this.initCalendarYear(this.primaryMonthPicker, this.currentYear);
    } else if (this.primaryMode === this.modes[1]) {
        this.initYearToDate(this.primaryMonthPicker, this.currentYear);
    } else if (this.primaryMode === this.modes[2]) {
        this.initRollingYear(this.primaryMonthPicker, this.currentYear);
    }
}

在上面的代码MonthpickerComponent中是另一个自定义组件,它是TimeselectorComponent的唯一子组件。

我只想检查何时调用primaryDropDown,然后再调用initCalendarYear。这是规格文件:

import { TestBed, ComponentFixture, async } from '@angular/core/testing';
import { TimeselectorComponent } from './timeselector.component';
...

describe('TimeselectorComponent', () => {
    let fixture: ComponentFixture<TimeselectorComponent>;

    @Component({
        selector: 'app-monthpicker',
        template: '<div></div>'
    })
    class FakeMonthpickerComponent {
        // methods of MonthpickerComponent
    }

    let MODES = [];

    beforeEach(async(() => {
        MODES = ['Calendar Year', 'Year-to-date', 'Rolling Year', 'Custom'];
        TestBed.configureTestingModule({
            declarations: [FakeMonthpickerComponent, TimeselectorComponent],
            schemas: [NO_ERRORS_SCHEMA]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(TimeselectorComponent);
    });

    // other test cases that are passing

    // need help with this test case
    it('should call initCalendarYear when primaryDropDown is called', () => {
      const startRange=moment('2020-01-01');
      const endRange= moment('2020-12-01');
      spyOn(fixture.componentInstance, 'initCalendarYear');
      fixture.componentInstance.primaryMode=MODES[0];
      fixture.componentInstance.primaryDropDown(startRange, endRange);
     expect(fixture.componentInstance.initCalendarYear).toHaveBeenCalled();
  });
});

但是我收到此错误: enter image description here

我必须测试是否为关联的if-else语句调用了正确的方法。请帮助我。

这里是stackblitz

2 个答案:

答案 0 :(得分:1)

import { TestBed, ComponentFixture, async } from '@angular/core/testing';
import { TimeselectorComponent } from './timeselector.component';
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
var moment = require('moment/moment')

describe('TimeselectorComponent', () => {
    let fixture: ComponentFixture<TimeselectorComponent>;

    @Component({
        selector: 'app-monthpicker',
        template: '<div></div>'
    })
    class FakeMonthpickerComponent {
        // methods of MonthpickerComponent
    }

    let MODES = [];

    beforeEach(async(() => {
        MODES = ['Calendar Year', 'Year-to-date', 'Rolling Year', 'Custom'];
        TestBed.configureTestingModule({
            declarations: [FakeMonthpickerComponent, TimeselectorComponent],
            schemas: [NO_ERRORS_SCHEMA]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(TimeselectorComponent);
    });

    // other test cases that are passing

    // need help with this test case
    it('should call initCalendarYear when primaryDropDown is called', () => {
      const startRange=moment('2020-01-01');
      const endRange= moment('2020-12-01');
      spyOn(fixture.componentInstance, 'initCalendarYear');
      fixture.componentInstance.primaryMode=MODES[0];
      fixture.componentInstance.primaryDropDown(startRange, endRange);
     expect(fixture.componentInstance.initCalendarYear).toHaveBeenCalled();
  });
});

以上游戏使我成功:-

enter image description here

enter image description here

答案 1 :(得分:1)

添加这样的间谍

spyOn(fixture.componentInstance, 'initCalendarYear');

以此更改最后一行

expect(fixture.componentInstance.initCalendarYear).toHaveBeenCalled();

因此您的最终测试用例应如下所示

it('should call initCalendarYear when primaryDropDown is called', () => {
        const startRange=moment('2020-01-01');
        const endRange= moment('2020-12-01');
        fixture.componentInstance.primaryMode = MODES[0];
        spyOn(fixture.componentInstance, 'initCalendarYear');
        fixture.componentInstance.primaryDropDown(startRange, endRange);

  expect(fixture.componentInstance.initCalendarYear).toHaveBeenCalled(); 
 });