在单元测试中无法访问Angular Service成员变量 [英] Angular Service Member Variable Not Accessible in Unit Tests
问题描述
我正在尝试测试Angular服务,该服务的一部分工作是加载一个JSON文件,该文件用作该服务的配置.我已经在测试中(通过console.log
确认),我正在模拟HTTP.get调用以获取配置的方式有效,并且正在返回模拟的配置对象:
I am trying to test my Angular service, and part of what the service does is load a JSON file that is used as configuration for the service. I have confirmed in the tests (through console.log
) that the way I am mocking the HTTP.get call to get the configuration is working and is returning the mocked config object:
// 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();
当我在loadInternalAuthModuleConfiguration
函数中使用console.log
时,我看到了上面显示的req.flush
中的对象和信息.在load
函数中,它采用该配置对象并将其值设置为服务中的私有变量:
When I console.log
in the loadInternalAuthModuleConfiguration
function, I see the object and information from the req.flush
shown above. In the load
function, it takes that configuration object and sets its value to a private variable in the service:
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
.我的问题出在下一步.
Again, console.log
shows that in the .then
method above that the configData
comes back properly and that it is set to be the this.internalConfigData
. My problem comes in the next step.
我想检查设置完之后是否可以从该configData
对象访问一个值. (请记住,我在beforeEach
中运行了load
函数.)我在服务中有一个函数getInternalConfig
和getInternalConfigValueByKey
,它们将返回整个配置对象或指定键的值.当我在测试中运行此命令时,对于internalConfigData
对象和传入的键的值,我都不确定.
I want to check that I can access a value from that configData
object after it's been set. (Remember that I ran the load
function in the beforeEach
.) I have a function in the service, getInternalConfig
and getInternalConfigValueByKey
that will either return the entire config object or a value for the specified key. When I run this in a test, I get undefined for the internalConfigData
object and for the value of the passed in key.
it('should be using testing-redirect as the redirectStorage', () => {
const configObj = authenticationService.getInternalConfig();
const redirectStorage = authenticationService.getInternalConfigValueByKey('redirectStorage');
expect(redirectStorage).toBe('testing-redirect');
});
该测试应该通过.如果我在load
函数中console.log
internalConfigData
对象,我可以看到我给它的对象.我不确定为什么this.internalConfigData
似乎在beforeEach
与测试运行之间丢失了数据.
That test should pass. If I console.log
the internalConfigData
object in the load
function I can see the object I've given it. I'm not sure why it seems that this.internalConfigData
is losing its data somewhere between beforeEach
and when my test runs.
我在这里缺少什么以确保此测试正确运行并通过?
What am I missing here to make sure that this test runs correctly and passes?
这也是TestBed.configureTestingModule
供参考:
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
AuthenticationService,
{ provide: AuthenticationConfig, useValue: mockAuthConfig },
{ provide: OidcConfigService, useValue: mockOidcConfigService },
{ provide: OidcSecurityService, useValue: mockOidcSecurityService },
{ provide: localStorage, useValue: mockLocalStorage },
],
});
编辑2
这是整个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');
});
推荐答案
此处的问题是您将http Observable转换为Promise,并且测试变为异步.这意味着,当代码到达it
语句时,您的服务尚未解析数据.
The problem here is that you transform http Observable to Promise and your test becomes asynchronous. It means that by the time the code reaches it
statement your service doesn't have data resolved yet.
如果您使用Observable,它将通过:
If you used Observable it would passed:
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,则必须等待所有微任务被执行:
If you still want to convert observable to promise you have to wait all microtasks to be executed:
import { TestBed, async } from '@angular/core/testing';
...
beforeEach(async(() => {
...
}));
这篇关于在单元测试中无法访问Angular Service成员变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!