我正在尝试测试Angular服务,该服务的一部分工作是加载一个JSON文件,该文件用作该服务的配置。我已经在测试中(通过console.log
确认,我正在模拟HTTP.get调用以获取配置的方式有效,并且正在返回模拟的配置对象:
// mocking the loading of the configuration in the beforeEach
authenticationService.loadInternalAuthModuleConfiguration();
const req = httpTestingController.expectOne('./internal-config.json');
req.flush({
redirectStorage: 'testing-redirect',
forbiddenStorage: 'testing-forbidden',
useAuthServerInDevelopment: true,
});
httpTestingController.verify();
当我在console.log
函数中loadInternalAuthModuleConfiguration
时,我看到了上面显示的req.flush
中的对象和信息。在load
函数中,它获取该配置对象并将其值设置为服务中的私有变量:
loadInternalAuthModuleConfiguration() {
return this._http
.get(this.authConfig.internalAuthModuleConfigUrl)
.toPromise()
.then((configData: any) => {
this.internalConfigData = { ...configData };
this.internalConfigSubject.next(this.internalConfigData);
this.setPrivateClassVariables();
})
.catch((err: any) => {
this.internalConfigData = null;
this.internalConfigSubject.next(this.internalConfigData);
});
}
同样,console.log
显示在上面的.then
方法中,configData
可以正确返回,并将其设置为this.internalConfigData
。我的问题出在下一步。
我想检查设置完之后是否可以从该configData
对象访问一个值。 (请记住,我在load
中运行过beforeEach
函数。)服务中有一个函数getInternalConfig
和getInternalConfigValueByKey
,它将返回整个配置对象或一个指定键的值。当我在测试中运行此命令时,internalConfigData
对象和传入键的值都未定义。
it('should be using testing-redirect as the redirectStorage', () => {
const configObj = authenticationService.getInternalConfig();
const redirectStorage = authenticationService.getInternalConfigValueByKey('redirectStorage');
expect(redirectStorage).toBe('testing-redirect');
});
该测试应该通过。如果我在console.log
函数中internalConfigData
load
对象,我可以看到我给它的对象。我不确定为什么this.internalConfigData
到beforeEach
到我的测试运行之间丢失了数据。
我在这里缺少什么以确保此测试正确运行并通过?
这里还有TestBed.configureTestingModule
供参考:
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
AuthenticationService,
{ provide: AuthenticationConfig, useValue: mockAuthConfig },
{ provide: OidcConfigService, useValue: mockOidcConfigService },
{ provide: OidcSecurityService, useValue: mockOidcSecurityService },
{ provide: localStorage, useValue: mockLocalStorage },
],
});
这是整个beforeEach
和相关测试:
beforeEach(() => {
mockOidcConfigService = jasmine.createSpyObj(['load']);
mockOidcSecurityService = jasmine.createSpyObj(['getIsAuthorized']);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
AuthenticationService,
{ provide: AuthenticationConfig, useValue: mockAuthConfig },
{ provide: OidcConfigService, useValue: mockOidcConfigService },
{ provide: OidcSecurityService, useValue: mockOidcSecurityService },
{ provide: localStorage, useValue: mockLocalStorage },
],
});
httpTestingController = TestBed.get(HttpTestingController);
authenticationService = TestBed.get(AuthenticationService);
store = {};
authenticationService.loadInternalAuthModuleConfiguration();
const req = httpTestingController.expectOne('./internal-config.json');
req.flush({
redirectStorage: 'testing-redirect',
forbiddenStorage: 'testing-forbidden',
useAuthServerInDevelopment: true,
});
httpTestingController.verify();
});
it('should be using testing-redirect as the redirectStorage', () => {
const configObj = authenticationService.getInternalConfig();
const redirectStorage = authenticationService.getInternalConfigValueByKey('redirectStorage');
expect(redirectStorage).toBe('testing-redirect');
});
答案 0 :(得分:4)
这里的问题是您将http Observable转换为Promise,并且测试变为异步。这意味着,当代码到达it
语句时,您的服务尚未解析数据。
如果使用Observable,它将通过:
loadInternalAuthModuleConfiguration() {
return this.http
.get(this.authConfig.internalAuthModuleConfigUrl)
.subscribe((configData: any) => {
this.internalConfigData = {...configData};
this.internalConfigSubject.next(this.internalConfigData);
this.setPrivateClassVariables();
}, (err: any) => {
this.internalConfigData = null;
this.internalConfigSubject.next(this.internalConfigData);
});
}
如果您仍然想将observable转换为promise,则必须等待所有微任务被执行:
import { TestBed, async } from '@angular/core/testing';
...
beforeEach(async(() => {
...
}));