如果我的方法返回的输出是正确的,为什么这个 Jasmine 单元测试总是失败(测试 Angular 组件)?



我第一次尝试用Jasmine调试Angular项目。

我有这个PeopleListComponent组件类:

import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
import { EventService } from '../event.service';
import interactionPlugin, { Draggable } from '@fullcalendar/interaction';
interface WorkShiftTypes {
name: string;
value: string;
}
@Component({
selector: 'app-people-list',
templateUrl: './people-list.component.html',
styleUrls: ['./people-list.component.css']
})
export class PeopleListComponent implements OnInit {
people: any[];
//cities: City[];
workShiftTypes: WorkShiftTypes[];
selectedShift: WorkShiftTypes;
@ViewChild('draggable_people') draggablePeopleExternalElement: ElementRef;
constructor(private eventService: EventService) { }
ngOnInit(): void {
this.eventService.getPeople().then(people => {this.people = people;});
this.selectedShift = {name: 'Mattina', value: 'Mattina'};
this.workShiftTypes = [
{name: 'Mattina', value: 'Mattina'},
{name: 'Pomeriggio', value: 'Pomeriggio'},
{name: 'Notte', value: 'Notte'},
{name: 'Custom', value: 'Custom'}
];
}
ngAfterViewInit() {
console.log("PEOPLE LIST ngAfterViewInit() START !!!")
var self = this
new Draggable(this.draggablePeopleExternalElement.nativeElement, {
itemSelector: '.fc-event',
eventData: function(eventEl) {
console.log("DRAG !!!");
//console.log("SELECTED SHIFT: " + self.selectedShift.value);
return {
title: eventEl.innerText,
startTime: "17:00",
duration: { hours: 8 }
};
}
});
}
createEventObject() {
console.log("createEventObject() START");
return 1;
}
}

如您所见,它包含以下简单方法,目前仅返回值 1:

createEventObject(( { console.log("createEventObject(( START"(; 返回 1; }

我想创建一个非常简单的 Jasmine 单元测试,断言此方法的返回值为 1。所以我实现了这个people-list.component.spec.ts文件:

import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import { PeopleListComponent } from "./people-list.component"
import { EventService } from '../event.service';
import {HttpClientTestingModule} from '@angular/common/http/testing';
describe('people-list', () => {
let component: PeopleListComponent;
let fixture: ComponentFixture<PeopleListComponent>;
let eventServiceSpy : jasmine.SpyObj<EventService>;
beforeEach(async(() => {
const eventServiceSpyObj = jasmine.createSpyObj('EventService',['getPeople'])
TestBed.configureTestingModule({
declarations: [PeopleListComponent],
imports: [HttpClientTestingModule],
providers : [{ provide : EventService, useValue : eventServiceSpyObj }]
});
// Create a testing version of my PeopleListComponent:
fixture = TestBed.createComponent(PeopleListComponent);
//eventServiceSpy = TestBed.inject(EventService);
eventServiceSpy = <jasmine.SpyObj<EventService>><any>TestBed.inject(EventService);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('createEventObject()  return 1', () => {
console.log("TEST 1 START");
var methodOutput = component.createEventObject();
console.log("METHOD OUTPUT: " + methodOutput);
expect(methodOutput).toBe(1);
//expect(1).toBe(1);
})
})

如您所见,我还在测试箭头函数中插入了一些console.log(( 语句以检查被调用的组件的输出.createEventObject((并且它正确返回 1。

问题是测试失败了,我不明白为什么。

在控制台中,我收到此错误消息:

developer@developer-virtual-machine:~/Documents/Angular-WS/SOC-Calendar$ ng test
10% building 2/2 modules 0 active23 05 2020 09:27:06.907:WARN [karma]: No captured browser, open http://localhost:9876/
23 05 2020 09:27:06.916:INFO [karma-server]: Karma v5.0.5 server started at http://0.0.0.0:9876/
23 05 2020 09:27:06.920:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
23 05 2020 09:27:06.927:INFO [launcher]: Starting browser Chrome
23 05 2020 09:27:12.013:WARN [karma]: No captured browser, open http://localhost:9876/
23 05 2020 09:27:12.211:INFO [Chrome 81.0.4044.129 (Linux x86_64)]: Connected on socket 0_E-_vH-y-N_pe-NAAAA with id 36927658
WARN: ''p-selectButton' is not a known element:
1. If 'p-selectButton' is an Angular component, then verify that it is part of this module.
2. If 'p-selectButton' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.'
Chrome 81.0.4044.129 (Linux x86_64): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
WARN: ''p-selectButton' is not a known element:
1. If 'p-selectButton' is an Angular component, then verify that it is part of this module.
2. If 'p-selectButton' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to supWARN: ''p-orderList' is not a known element:
1. If 'p-orderList' is an Angular component, then verify that it is part of this module.
2. If 'p-orderList' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.'
Chrome 81.0.4044.129 (Linux x86_64): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
WARN: ''p-orderList' is not a known element:
1. If 'p-orderList' is an Angular component, then verify that it is part of this module.
2. If 'p-orderList' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppreLOG: 'TEST 1 START'
Chrome 81.0.4044.129 (Linux x86_64): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
LOG: 'createEventObject() START'
Chrome 81.0.4044.129 (Linux x86_64): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
LOG: 'METHOD OUTPUT: 1'
Chrome 81.0.4044.129 (Linux x86_64): Executed 0 of 1 SUCCESS (0 secs / 0 secs)
Chrome 81.0.4044.129 (Linux x86_64) people-list createEventObject()  return 1 FAILED
Failed: Cannot read property 'then' of undefined
at <Jasmine>
at PeopleListComponent.ngOnInit (http://localhost:9876/_karma_webpack_/src/app/people-list/people-list.component.ts:29:34)
at callHook (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4770:1)
at callHooks (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4734:1)
at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4674:1)
at refreshView (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:11998:1)
at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:12114:1)
at tickRootContext (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:13668:1)
at detectChangesInRootView (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:13702:1)
at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:15420:1)
at ComponentFixture._tick (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:331:1)
Chrome 81.0.4044.129 (Linux x86_64): Executed 1 of 1 (1 FAILED) (0 secs / 0.055 secs)
Chrome 81.0.4044.129 (Linux x86_64) people-list createEventObject()  return 1 FAILED
Failed: Cannot read property 'then' of undefined
at <Jasmine>
at PeopleListComponent.ngOnInit (http://localhost:9876/_karma_webpack_/src/app/people-list/people-list.component.ts:29:34)
at callHook (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4770:1)
at callHooks (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4734:1)
at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:4674:1)
at refreshView (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:11998:1)
at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:12114:1)
at tickRootContext (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:13668:1)
at detectChangesInRootView (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:13702:1)
at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:15420:1)
at ComponentFixture._tick (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/tChrome 81.0.4044.129 (Linux x86_64): Executed 1 of 1 (1 FAILED) (0.105 secs / 0.055 secs)
TOTAL: 1 FAILED, 0 SUCCESS
TOTAL: 1 FAILED, 0 SUCCESS

我还试图替换:

expect(methodOutput).toBe(1);

跟:

expect(1).toBe(1);

以确保测试成功,但我仍然得到相同的错误,所以我认为问题与这个excpect-toBe行无关,而是与我的测试的某些配置有关。

为什么我会收到这个奇怪的错误?这到底是什么意思?我的代码有什么问题?我该如何解决它?

我看到几个问题,可以描述为测试模块配置不正确。

  • 该组件包含多个依赖项。如p-selectButtonp-orderList等。Angular试图解决这些问题并失败了。解决方法 - 告诉 Angular 避免解析这些标记。
TestBed.configureTestingModule({
...
schemas:[NO_ERRORS_SCHEMA],
});
  • fixture.detectChanges()触发组件生命周期事件。ngOnInit其中之一。错误发生在那里:
Failed: Cannot read property 'then' of undefined
at <Jasmine>
at PeopleListComponent.ngOnInit 

ngOnInit里面只有一个then

this.eventService.getPeople().then(people => {this.people = people;});

现在让我们看看提供的模拟:

const eventServiceSpyObj = jasmine.createSpyObj('EventService',['getPeople'])
{ provide : EventService, useValue : eventServiceSpyObj }

似乎创建的间谍eventServiceSpyObj具有getPeople()的方法。读取错误Cannot read property 'then' of undefined很明显,getPeople()返回undefined而不是承诺。要解决此问题,您需要模拟getPeople的返回值

const eventServiceSpyObj = jasmine.createSpyObj('EventService',['getPeople'])
eventServiceSpyObj.getPeople.and.returnValue(Promise.resolve());

或者不要调用该方法fixture.detectChanges()。此测试不需要它。

最新更新