Unit testing 模拟服务时出现测试错误(角度2)
我有一个组件,它使用一个服务返回一个可观察的。我没有在Jasmine测试中连接此服务,而是选择监视一个模拟 以下是NumProbesService[numprobes.service.ts],它使用Http从web服务器获取JSON响应:Unit testing 模拟服务时出现测试错误(角度2),unit-testing,angular,jasmine,observable,Unit Testing,Angular,Jasmine,Observable,我有一个组件,它使用一个服务返回一个可观察的。我没有在Jasmine测试中连接此服务,而是选择监视一个模拟 以下是NumProbesService[numprobes.service.ts],它使用Http从web服务器获取JSON响应: import { Injectable } from '@angular/core'; import { Http, Response, Headers, RequestOptions } from '@angular/http'; import {Obser
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map'
import {ProbeCount} from "./probecount.model";
@Injectable()
export class NumProbesService {
private numProbesUrl = 'http://localhost:9090/getnumberofprobes';
private probeCount: ProbeCount;
constructor (private http: Http) {}
createAuthorizationHeader(headers: Headers) {
headers.append('X-Auth-Key', 'mjones');
headers.append('X-Auth-Secret', '111111-2222222-22222-3233-4444444');
}
public getProbeCount() : Observable<ProbeCount> {
let headers = new Headers();
this.createAuthorizationHeader(headers);
return this.http.get(this.numProbesUrl, {headers: headers})
.map((response:Response) => this.probeCount = <ProbeCount>response.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
}
我正在测试的组件如下所示:
import {Component, Input} from '@angular/core';
import {NumProbesService} from './numprobes.service';
import {ProbeCount} from "./probecount.model";
@Component({
selector: 'numprobes-box',
templateUrl: './numprobes.component.html'
})
export class NumProbesComponent {
name: string;
numprobes: number;
probeCount: ProbeCount;
constructor(private numProbesService: NumProbesService) {
}
ngOnInit() {
this.name = "Number of Probes";
this.numProbesService.getProbeCount().subscribe(
(probeCount) => {
console.log("probeCount: " + JSON.stringify(probeCount));
console.log(probeCount.total_probe_count);
this.numprobes = probeCount.total_probe_count;
}
);
}
}
最后,这里是组件的实际测试
import {By} from '@angular/platform-browser';
import {DebugElement} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {NumProbesService} from './numprobes.service';
import {NumProbesMockService} from './numprobes.service.mock';
import {NumProbesComponent} from './numprobes.component';
import {ProbeInfo} from './probeinfo.model';
describe('NumProbesComponent', () => {
let comp: NumProbesComponent;
let fixture: ComponentFixture<NumProbesComponent>;
let spy: jasmine.Spy;
let de: DebugElement;
let el: HTMLElement;
let numProbesService: NumProbesService; // the actually injected service
const numProbes = 5;
let probeInfo : ProbeInfo = new ProbeInfo(numProbes);
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [NumProbesComponent],
providers: [
{ provide: NumProbesService, useClass: NumProbesMockService }
]
});
fixture = TestBed.createComponent(NumProbesComponent);
comp = fixture.componentInstance;
numProbesService = fixture.debugElement.injector.get(NumProbesService);
spy = spyOn(numProbesService, 'getProbeCount')
.and.returnValue(probeInfo);
});
it('Should show the label within component', () => {
de = fixture.debugElement.query(By.css(".info-box-text"));
el = de.nativeElement;
fixture.detectChanges();
expect(el.textContent).toBe('Number of Probes', 'Label displayed');
});
it('should show the name of the info box, "Number of Probes"', () => {
de = fixture.debugElement.query(By.css(".info-box-number"));
el = de.nativeElement;
console.log("el.textContent: " + el.textContent);
expect(el).toBeDefined();
expect(el.textContent).toBe('', 'nothing displayed');
let probeInfoCalled = numProbesService.getProbeCount();
expect(spy.calls.any()).toBe(true, 'getProbeCount not yet called');
});
}
您得到的错误是由于间谍覆盖了原始方法造成的 换句话说,在执行这一行之后:
spyOn(numprobservice,'getProbeCount')
numprobservice.getProbeCount
不再引用返回可观察对象的原始方法,而是引用间谍
我设置了一个测试我的答案,它按预期工作:如果你评论了间谍,你将能够再次订阅:
//app.component.spec.ts
beforeach(异步(()=>{
ps=fixture.debugElement.injector.get(ProbeService);
//间谍会覆盖ps.getProbeCount()方法。
//间谍(ps,'getProbeCount');
//触发初始数据绑定
fixture.detectChanges();
}));
它('应该返回5',(完成)=>{
//如果间谍被陷害了,这是行不通的。
ps.getProbeCount().subscribe(val=>{
期望值(val)、toEqual(5);
完成();
});
});
它('应该被调用',()=>{
//这只有在间谍被陷害的情况下才能起作用。
expect(ps.getProbeCount).tohavebeincall();
});
但正如我在评论中所说,你正在做两次同样的事情。使用spy或mock返回mock值,但不能同时使用两者。如果在订阅之前立即使用console.log
numProbesService.getProbeCount
,您会看到什么?旁注:你的spy和mock似乎做了两次同样的事情:既然你的mock已经返回了mock数据,为什么你还需要spy来返回mock数据?@AngularFrance,我添加了console.log(this.numProbesService.getProbeCount())
调用subscribe()之前的组件,并获得LOG:ProbeInfo{}
。这是否意味着在调用getProbeCount()时,我不会从模拟服务中得到可观察的结果?该方法显然返回可观察的。你知道我可能出了什么问题吗?你能告诉我你想在测试中验证什么吗?(没有提及您是如何尝试的,我很想知道您是如何尝试的)@AngularFrance,我试图验证1)作为组件属性的信息框标签是否出现在信息框html中,2)探测数(ProbeCount对象的属性)匹配模拟服务返回的数字。是的!成功了。我既是间谍又是嘲弄,我应该这样做或那样做。我除掉了间谍,用了模拟软件,一切正常。太好了。如果您不介意,请将答案标记为“正确”,以便StackOverflow上的其他人将来可以使用它。谢谢你,梅尔文!
import {Component, Input} from '@angular/core';
import {NumProbesService} from './numprobes.service';
import {ProbeCount} from "./probecount.model";
@Component({
selector: 'numprobes-box',
templateUrl: './numprobes.component.html'
})
export class NumProbesComponent {
name: string;
numprobes: number;
probeCount: ProbeCount;
constructor(private numProbesService: NumProbesService) {
}
ngOnInit() {
this.name = "Number of Probes";
this.numProbesService.getProbeCount().subscribe(
(probeCount) => {
console.log("probeCount: " + JSON.stringify(probeCount));
console.log(probeCount.total_probe_count);
this.numprobes = probeCount.total_probe_count;
}
);
}
}
import {By} from '@angular/platform-browser';
import {DebugElement} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {NumProbesService} from './numprobes.service';
import {NumProbesMockService} from './numprobes.service.mock';
import {NumProbesComponent} from './numprobes.component';
import {ProbeInfo} from './probeinfo.model';
describe('NumProbesComponent', () => {
let comp: NumProbesComponent;
let fixture: ComponentFixture<NumProbesComponent>;
let spy: jasmine.Spy;
let de: DebugElement;
let el: HTMLElement;
let numProbesService: NumProbesService; // the actually injected service
const numProbes = 5;
let probeInfo : ProbeInfo = new ProbeInfo(numProbes);
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [NumProbesComponent],
providers: [
{ provide: NumProbesService, useClass: NumProbesMockService }
]
});
fixture = TestBed.createComponent(NumProbesComponent);
comp = fixture.componentInstance;
numProbesService = fixture.debugElement.injector.get(NumProbesService);
spy = spyOn(numProbesService, 'getProbeCount')
.and.returnValue(probeInfo);
});
it('Should show the label within component', () => {
de = fixture.debugElement.query(By.css(".info-box-text"));
el = de.nativeElement;
fixture.detectChanges();
expect(el.textContent).toBe('Number of Probes', 'Label displayed');
});
it('should show the name of the info box, "Number of Probes"', () => {
de = fixture.debugElement.query(By.css(".info-box-number"));
el = de.nativeElement;
console.log("el.textContent: " + el.textContent);
expect(el).toBeDefined();
expect(el.textContent).toBe('', 'nothing displayed');
let probeInfoCalled = numProbesService.getProbeCount();
expect(spy.calls.any()).toBe(true, 'getProbeCount not yet called');
});
}
Chrome 56.0.2924 (Mac OS X 10.10.5) NumProbesComponent Should show the label within component FAILED
Error: Error in :0:0 caused by: this.numProbesService.getProbeCount(...).subscribe is not a function
at ViewWrappedError.ZoneAwareError (webpack:///~/zone.js/dist/zone.js:811:0 <- src/test.ts:106351:33)
at ViewWrappedError.BaseError [as constructor] (webpack:///~/@angular/core/src/facade/errors.js:26:0 <- src/test.ts:6476:16)
at ViewWrappedError.WrappedError [as constructor] (webpack:///~/@angular/core/src/facade/errors.js:88:0 <- src/test.ts:6538:16)
at new ViewWrappedError (webpack:///~/@angular/core/src/linker/errors.js:73:0 <- src/test.ts:60069:16)
at CompiledTemplate.proxyViewClass.DebugAppView._rethrowWithContext (webpack:///~/@angular/core/src/linker/view.js:650:0 <- src/test.ts:84195:23)
at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (webpack:///~/@angular/core/src/linker/view.js:623:0 <- src/test.ts:84168:18)
at ViewRef_.detectChanges (webpack:///~/@angular/core/src/linker/view_ref.js:179:0 <- src/test.ts:61015:20)
at ComponentFixture._tick (webpack:///~/@angular/core/bundles/core-testing.umd.js:191:0 <- src/test.ts:12899:36)
at webpack:///~/@angular/core/bundles/core-testing.umd.js:205:45 <- src/test.ts:12913:53
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:242:0 <- src/test.ts:105782:26)
at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:79:0 <- src/test.ts:71475:39)
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:241:0 <- src/test.ts:105781:32)
at Object.onInvoke (webpack:///~/@angular/core/src/zone/ng_zone.js:269:0 <- src/test.ts:31712:37)
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:241:0 <- src/test.ts:105781:32)
at Zone.run (webpack:///~/zone.js/dist/zone.js:113:0 <- src/test.ts:105653:43)