如果我的方法返回的输出是正确的,为什么这个 Jasmine 单元测试总是失败(测试 Angular 组件)?
Why this Jasmine unit test always fail (testing an Angular component) also if the output returned by my method is correct?
我第一次尝试使用 Jasmine 调试 Angular 项目。
我有这个 PeopleListComponent 组件 class:
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;
}
}
如您所见,它包含这个简单的方法,目前只是 return 值 1:
createEventObject() {
console.log("createEventObject() START");
return1个;
}
我想创建一个非常简单的 Jasmine 单元测试,断言此方法的 returned 值为 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() 语句来检查被调用 [ 的输出=56=]() 正确的是 return 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-selectButton
、p-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()
return undefined
而不是 Promise。要处理此问题,您需要模拟 getPeople
的 return 值
const eventServiceSpyObj = jasmine.createSpyObj('EventService',['getPeople'])
eventServiceSpyObj.getPeople.and.returnValue(Promise.resolve());
或者不调用方法 fixture.detectChanges()
。此测试不需要它。
我第一次尝试使用 Jasmine 调试 Angular 项目。
我有这个 PeopleListComponent 组件 class:
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;
}
}
如您所见,它包含这个简单的方法,目前只是 return 值 1:
createEventObject() { console.log("createEventObject() START"); return1个; }
我想创建一个非常简单的 Jasmine 单元测试,断言此方法的 returned 值为 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() 语句来检查被调用 [ 的输出=56=]() 正确的是 return 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-selectButton
、p-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()
return undefined
而不是 Promise。要处理此问题,您需要模拟 getPeople
const eventServiceSpyObj = jasmine.createSpyObj('EventService',['getPeople'])
eventServiceSpyObj.getPeople.and.returnValue(Promise.resolve());
或者不调用方法 fixture.detectChanges()
。此测试不需要它。