首先抱歉我的英语。
我正在使用Angular并通过他的测试开发一个简单的服务。
该服务使用http.get方法加载JSON文件并将其内容存储在变量中。 目标并不重要。
下面有效的代码:
首先是服务
import {Http} from '@angular/http';
import {Injectable} from '@angular/core';
import {Constants} from 'config/constants';
import 'rxjs/Rx';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class LoadJsonFileService {
private config: Object = null;
constructor(private http: Http) {
}
private loadJsonAndUpdateConfig() {
this.http
.get(Constants.CONFIG_FILE_NAME)
.map(response => response.json())
.catch((error: any): any => {
return Observable.throw(error.json().error || 'Server error');
}).subscribe((configJson) => {
this.config = configJson;
});
}
public getConfig(key: string): string {
if (!this.config) {
this.loadJsonAndUpdateConfig();
}
return this.config[key];
}
}
然后测试:
import {BaseRequestOptions, ConnectionBackend, Http, RequestOptions, Response, ResponseOptions} from '@angular/http';
import {MockBackend, MockConnection} from '@angular/http/testing';
import {LoadJsonFileService} from './load-json-file.service';
import {inject, TestBed} from '@angular/core/testing';
describe('Test suite ...', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{provide: RequestOptions, useClass: BaseRequestOptions},
{provide: ConnectionBackend, useClass: MockBackend},
Http,
LoadJsonFileService
]
});
});
it('The test ...', inject([ConnectionBackend, LoadJsonFileService],
(backend,
service: LoadJsonFileService) => {
backend.connections.subscribe((c: MockConnection) => {
c.mockRespond(new Response(new ResponseOptions({body: {key: 'foo'}})));
});
expect(service.getConfig('key')).toBe('foo');
}));
});
测试确定。
代码不起作用,我不知道原因:
import {Http} from '@angular/http';
import {Injectable} from '@angular/core';
import {Constants} from 'config/constants';
import 'rxjs/Rx';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class LoadJsonFileService {
private config: Object = null;
constructor(private http: Http) {
this.loadJsonAndUpdateConfig();
}
private loadJsonAndUpdateConfig() {
this.http
.get(Constants.CONFIG_FILE_NAME)
.map(response => response.json())
.catch((error: any): any => {
return Observable.throw(error.json().error || 'Server error');
}).subscribe((configJson) => {
this.config = configJson;
});
}
public getConfig(key: string): string {
return this.config[key];
}
}
区别在于构造函数中的this.loadJsonAndUpdateConfig()调用而不是getConfig方法。 测试失败:
TypeError: null is not an object (evaluating 'this.config[key]')
当我进行一些调试时,订阅方法永远不会触发,就像http.get从不调用...
我很困惑有人能解释我这种行为吗?
谢谢,
燕姿
答案 0 :(得分:0)
长话短说,只需为变量
指定默认值即可private config: Object = {};
长版本:第一个代码示例也不应该工作,除非你在某个地方为config
变量分配了一些东西,或者在this.config[key]
件执行之前后端请求完成(竞争条件),但是如果是在本地(或在测试中)工作,它可能在服务器上中断。
基本上,在getConfig()
之前调用this.config = configJson;
(我假设在模板中)。 Http请求是" async",即js / ts / angular不等到它完成后,后续代码在http请求启动后立即执行。
如果要测试它,请在返回值之前添加异步超时,或者更好地查看InMemoryWebApiModule
上的角度文档