为什么我在 Jasmine 单元测试中遇到此错误?
Why am I obtaining this error on my Jasmine unit test?
我正在尝试使用 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() {
return 1;
}
}
如您所见,它包含这个非常简单的 createEventObject() 方法,目前只有 return 1(我想尽可能简单).我的第一个单元测试必须测试此方法,只需检查 returned 值为 1.
如您所见,前面的方法在构造函数中注入了一个 EventService 服务实例。
这是 EventSerive class 代码:
import { Injectable } from '@angular/core';
//import { Http } from '@angular/http';
import { HttpClientModule, HttpClient } from '@angular/common/http'
@Injectable()
export class EventService {
private events = [
{id: 1, title: 'All Day Event', start: '2017-02-01'},
{id: 2, title: 'Long Event', start: '2017-02-07', end: '2017-02-10'},
{id: 3, title: 'Repeating Event', start: '2017-02-09T16:00:00'},
];
private people = [
{id: 1, name: "PERSONA 1"},
{id: 2, name: "PERSONA 2"},
{id: 3, name: "PERSONA 3"},
{id: 4, name: "PERSONA 4"},
{id: 5, name: "PERSONA 5"},
]
constructor(private http: HttpClient) {}
/*
getEvents(): Promise<any[]> {
return this.http.get('assets/json_mock/calendarevents.json')
.toPromise()
.then(res => JSON.parse(JSON.stringify(res)).data)
.then(res => {
console.log(res);
// you returned no value here!
return res;
})
}
*/
getEvents(): Promise<any[]> {
return Promise.all(this.events)
.then(res => {
console.log(res);
// you returned no value here!
return res;
})
}
addEvent(event) {
//this.events.push(event);
//console.log("EVENT:")
//console.log(event.event.title);
console.log(event.event.start);
console.log(event);
const newEvent = {id: 5, title: event.event.title, start: event.event.start, end: event.event.end};
this.events.push(newEvent);
console.log(this.events);
}
getPeople(): Promise<any[]> {
return Promise.all(this.people)
.then(res => {
console.log(res);
return res;
})
}
}
如您所见,此方法本身将另一个对象注入构造函数(HttpClient 以执行 HTTP 请求)。
好的,现在我想在我的单元测试中实现 createEventObject() 方法测试。所以我有这个 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);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('createEventObject() return 1', () => {
expect(component.createEventObject()).toBe(1)
})
})
我完全不确定它在逻辑上是否正确...
问题是目前IDE在这一行给我一个错误:
eventServiceSpy = TestBed.inject(EventService);
错误是:
Type 'EventService' is not assignable to type 'SpyObj<EventService>'.
Type 'EventService' is not assignable to type '{ getEvents: (() => Promise<any[]>) & Spy<() => Promise<any[]>>; addEvent: ((event: any) => void) & Spy<(event: any) => void>; getPeople: (() => Promise<any[]>) & Spy<...>; }'.
Types of property 'getEvents' are incompatible.
Type '() => Promise<any[]>' is not assignable to type '(() => Promise<any[]>) & Spy<() => Promise<any[]>>'.
Type '() => Promise<any[]>' is missing the following properties from type 'Spy<() => Promise<any[]>>': and, calls, withArgsts(2322)
怎么了?如何正确测试我的组件方法?
TypeScript 工具没那么聪明。
let eventServiceSpy : jasmine.SpyObj<EventService>;
eventServiceSpy = TestBed.inject(EventService);
eventServiceSpy
是 jasmine.SpyObj<EventService>;
类型。根据键入方法 TestBed.inject(EventService);
预计 return 类型 EventService
的对象,而使用 Angular DI 可以为任何注入令牌提供任何对象(在这种情况下注入令牌是 class EventService
)。上面你提供了 jasmine.SpyObj<EventService>
:
类型的对象
providers : [{ provide : EventService, useValue : eventServiceSpyObj }
所以现在方法 TestBed.inject(EventService);
将提供类型 jasmine.SpyObj<EventService>
的对象。但是到目前为止,开发工具还不够智能,无法正确处理此处的输入。
解决方法是铸造:
eventServiceSpy = <jasmine.SpyObj<EventService>><any>TestBed.inject(EventService);
我正在尝试使用 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() {
return 1;
}
}
如您所见,它包含这个非常简单的 createEventObject() 方法,目前只有 return 1(我想尽可能简单).我的第一个单元测试必须测试此方法,只需检查 returned 值为 1.
如您所见,前面的方法在构造函数中注入了一个 EventService 服务实例。
这是 EventSerive class 代码:
import { Injectable } from '@angular/core';
//import { Http } from '@angular/http';
import { HttpClientModule, HttpClient } from '@angular/common/http'
@Injectable()
export class EventService {
private events = [
{id: 1, title: 'All Day Event', start: '2017-02-01'},
{id: 2, title: 'Long Event', start: '2017-02-07', end: '2017-02-10'},
{id: 3, title: 'Repeating Event', start: '2017-02-09T16:00:00'},
];
private people = [
{id: 1, name: "PERSONA 1"},
{id: 2, name: "PERSONA 2"},
{id: 3, name: "PERSONA 3"},
{id: 4, name: "PERSONA 4"},
{id: 5, name: "PERSONA 5"},
]
constructor(private http: HttpClient) {}
/*
getEvents(): Promise<any[]> {
return this.http.get('assets/json_mock/calendarevents.json')
.toPromise()
.then(res => JSON.parse(JSON.stringify(res)).data)
.then(res => {
console.log(res);
// you returned no value here!
return res;
})
}
*/
getEvents(): Promise<any[]> {
return Promise.all(this.events)
.then(res => {
console.log(res);
// you returned no value here!
return res;
})
}
addEvent(event) {
//this.events.push(event);
//console.log("EVENT:")
//console.log(event.event.title);
console.log(event.event.start);
console.log(event);
const newEvent = {id: 5, title: event.event.title, start: event.event.start, end: event.event.end};
this.events.push(newEvent);
console.log(this.events);
}
getPeople(): Promise<any[]> {
return Promise.all(this.people)
.then(res => {
console.log(res);
return res;
})
}
}
如您所见,此方法本身将另一个对象注入构造函数(HttpClient 以执行 HTTP 请求)。
好的,现在我想在我的单元测试中实现 createEventObject() 方法测试。所以我有这个 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);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('createEventObject() return 1', () => {
expect(component.createEventObject()).toBe(1)
})
})
我完全不确定它在逻辑上是否正确...
问题是目前IDE在这一行给我一个错误:
eventServiceSpy = TestBed.inject(EventService);
错误是:
Type 'EventService' is not assignable to type 'SpyObj<EventService>'.
Type 'EventService' is not assignable to type '{ getEvents: (() => Promise<any[]>) & Spy<() => Promise<any[]>>; addEvent: ((event: any) => void) & Spy<(event: any) => void>; getPeople: (() => Promise<any[]>) & Spy<...>; }'.
Types of property 'getEvents' are incompatible.
Type '() => Promise<any[]>' is not assignable to type '(() => Promise<any[]>) & Spy<() => Promise<any[]>>'.
Type '() => Promise<any[]>' is missing the following properties from type 'Spy<() => Promise<any[]>>': and, calls, withArgsts(2322)
怎么了?如何正确测试我的组件方法?
TypeScript 工具没那么聪明。
let eventServiceSpy : jasmine.SpyObj<EventService>;
eventServiceSpy = TestBed.inject(EventService);
eventServiceSpy
是 jasmine.SpyObj<EventService>;
类型。根据键入方法 TestBed.inject(EventService);
预计 return 类型 EventService
的对象,而使用 Angular DI 可以为任何注入令牌提供任何对象(在这种情况下注入令牌是 class EventService
)。上面你提供了 jasmine.SpyObj<EventService>
:
providers : [{ provide : EventService, useValue : eventServiceSpyObj }
所以现在方法 TestBed.inject(EventService);
将提供类型 jasmine.SpyObj<EventService>
的对象。但是到目前为止,开发工具还不够智能,无法正确处理此处的输入。
解决方法是铸造:
eventServiceSpy = <jasmine.SpyObj<EventService>><any>TestBed.inject(EventService);