问题描述
这是我在angular 7中的第一个单元测试,我想在我的服务中测试我的方法,该方法返回 Observable :
this is my first unit test in angular 7, i want to test my methode inside my service, this methode return Observable:
fetchData(chronoInfo: ALChrono): Observable<any> {
// construct API parameters and URL
var URL: string = this.urlDecoratorService.urlAPIDecorate("AL", "GetAccessChrono");
var params = this.urlDecoratorService.generateParameters({
year: chronoInfo.year,//Année
month: chronoInfo.month,//Mois (peut être null)
sortBy: chronoInfo.sortBy,// Champ de tri
sortDirection: chronoInfo.sortDirection,//True pour inverser l'ordre de tri
pageNumber: chronoInfo.currentPage,//Page de résultats
pageSize: chronoInfo.pageSize//Nb enregistrements par page
});
return this.apiFetcher.fetchJson(URL, params);
//retourne les AL par année & mois
}
此方法的测试是:
import { TestBed, async, inject } from '@angular/core/testing';
import { AnnonceChronoDetailService } from './annonce-chrono-detail.service';
import { HttpClientModule } from '@angular/common/http';
import { UrlDecoratorService } from "src/app/common/url-decorator.service";
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { APIFetcherService } from "src/app/services/common/api-fetcher.service";
import { Http, ConnectionBackend, RequestOptions, HttpModule } from "@angular/http";
import { ALChrono } from '../../common/IALChrono.interface';
import { Observable } from 'rxjs';
describe('AnnonceChronoDetailService', () => {
let service: AnnonceChronoDetailService;
let alChrono: ALChrono = { //it's an interface'
year: 2012,
month: -1,
sortBy: 'asc',
sortDirection: true,
currentPage: 1,
pageSize: 15
}
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
AnnonceChronoDetailService,
UrlDecoratorService,
APIFetcherService,
Http,
ConnectionBackend]
});
});
it('should be created', inject([AnnonceChronoDetailService], (service: AnnonceChronoDetailService) => {
expect(service).toBeTruthy();
}
));
it('#fetchData should return value from observable', (done: DoneFn) => {
service.fetchData(alChrono).subscribe(value => {
expect(value).toBe('observable value');
done();
});
});
});
当我执行ng test
时,我在第二次测试#fetchData should return value from observable
中遇到问题,错误是:
and when i execute ng test
i have problem in the seconde test #fetchData should return value from observable
, the error is :
AnnonceChronoDetailService > #fetchData should return value from observable
TypeError: Cannot read property 'fetchData' of undefined
at <Jasmine>
at UserContext.<anonymous> (http://localhost:9876/src/app/services/annonce-legale/annonce-chrono-detail.service.spec.ts?:41:17)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/node_modules/zone.js/dist/zone.js?:388:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:288:1)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/node_modules/zone.js/dist/zone.js?:387:1)
at Zone../node_modules/zone.js/dist/zone.js.Zone.run (http://localhost:9876/node_modules/zone.js/dist/zone.js?:138:1)
at runInTestZone (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:506:1)
at UserContext.<anonymous> (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:522:1)
at <Jasmine>
我尝试了一些解决方案,例如添加asyn
,但问题是相同的.
i try some solutions like adding asyn
but the problem was the same.
推荐答案
您在第一个规范中定义了服务"("it"功能),然后在第二个规范中尝试使用了它.如果您想在每个规范中使用'service'变量,这很有意义,那么我建议您在beforeEach函数中放置类似这样的内容,以便为每个规范正确定义服务:
You define 'service' in the first spec ('it' function) but then try and use it in the second. If you want to use the 'service' variable within each spec, which makes sense, then I would suggest you put something like this inside the beforeEach function to define service correctly for every spec:
service = TestBed.get(AnnonceChronoDetailService);
然后将您的第一个规格更改为以下内容:
Then change your first spec to the following:
it('should be created', () => {
expect(service).toBeTruthy();
});
现在,您的第二个规格应该可以按书面要求工作.
Now your second spec should work as written.
为其他服务添加间谍.有很多方法可以做到这一点.这是一个:
Adding spies for your other services. Many ways to do this. Here is one:
describe('AnnonceChronoDetailService', () => {
const spyDecorator = jasmine.createSpyObj('UrlDecoratorService', {
urlAPIDecorate: '/test/url',
generateParameters: null /* set test params to return here /*
};
const spyFetcher = jasmine.createSpyObj('APIFetcherService', {
fetchJson: {}
};
let service: AnnonceChronoDetailService;
...
现在将提供程序数组更改为使用间谍而不是原始服务:
Now change your providers array to use the spies instead of the original services:
providers: [
AnnonceChronoDetailService,
{ provide: UrlDecoratorService, useValue: spyDecorator } ,
{ provide: APIFetcherService, useValue: spyFetcher },
]
,然后在您的说明文件中,您可以检查那些间谍.将这些建议更改为您真正关心的事情:
and then in your spec files you can check those spies. Change these suggestions to something you actually care about:
it('#fetchData should return value from observable', () => {
spyFetcher.fetchJson.and.returnValue(of('observable value'));
service.fetchData(alChrono).subscribe(value => {
expect(value).toEqual('observable value');
});
expect(spyDecorator.urlAPIDecorate).toHaveBeenCalled();
expect(spyDecorator.generateParameters).toHaveBeenCalledTimes(1);
expect(spyFetcher.fetchJson).toHaveBeenCalledWith('/test/url', /* test params defined above */);
});
这篇关于TypeError:无法读取未定义的茉莉花业力的属性"fetchData"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!