在单元测试中无法访问Angular Service成员变量 [英] Angular Service Member Variable Not Accessible in Unit Tests

查看:55
本文介绍了在单元测试中无法访问Angular Service成员变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试测试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函数.)我在服务中有一个函数getInternalConfiggetInternalConfigValueByKey,它们将返回整个配置对象或指定键的值.当我在测试中运行此命令时,对于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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆