模块构造函数中的Angular 5测试代码

时间:2017-12-08 01:46:52

标签: angular testing jasmine

我正在尝试测试我的模块的一个构造函数中的代码。基本上,模块(名为GraphqlModule)配置服务(名为Graphql)并提供它。配置发生在模块的构造函数中。

这是我用来测试模块的代码。

it('should use the GraphqlConfigs and ServerConfigs', (done: DoneFn) => {

    // Adding spies to Config classes
    let serverConfigs = new ServerConfigs();
    let serverDomainSpy = spyOnProperty(serverConfigs, 'ServerDomain', 'get').and.callThrough();
    let serverPortSpy = spyOnProperty(serverConfigs, 'ServerPort', 'get').and.callThrough();

    let gqlConfigs = new GraphqlConfigs();
    let protocolSpy = spyOnProperty(gqlConfigs, 'EndpointProtocol', 'get').and.callThrough();
    let endpointNameSpy = spyOnProperty(gqlConfigs, 'EndpointName', 'get').and.callThrough();

    TestBed.configureTestingModule({
        imports: [ GraphqlModule ],
        providers: [
            {provide: ServerConfigs, useValue: serverConfigs}, // Replacing real config classes with the ones spied on.
            {provide: GraphqlConfigs, useValue: gqlConfigs}
        ]

    }).compileComponents().then(() => {

        // This line seems to make Angular instantiate GraphqlModule
        const graphql = TestBed.get(Graphql) as Graphql;

        expect(serverDomainSpy.calls.count()).toBe(1, 'ServerConfigs.ServerDomain was not used.');
        expect(serverPortSpy.calls.count()).toBe(1,  'ServerConfigs.ServerPort was not used.');

        expect(protocolSpy.calls.count()).toBe(1, 'GraphqlConfigs.EndpointProtocol was not used.');
        expect(endpointNameSpy.calls.count()).toBe(1,  'GraphqlConfigs.EndpointName was not used.');

        done();
    });
});

原样,测试通过并运行,但如果我不使用以下(无用)行const graphql = TestBed.get(Graphql) as Graphql;GraphqlModule会在执行测试后实例化,这会导致测试失败。 / p>

由于提供GraphqlModule服务的Graphql,我知道Angular中有一些延迟加载算法,当我执行TestBed.get(Graphql)时会触发。这很好......我的问题是,有没有办法让我的模块以更强烈的显式方式加载?

这是GraphqlModule类定义:

imports...

@NgModule({
    imports: [
        CommonModule,
        HttpClientModule,
        ApolloModule,
        HttpLinkModule
    ],
    declarations: [],

    providers: [
        Graphql, // Is an alias for Apollo
        GraphqlConfigs
    ]
})
export class GraphqlModule {

    constructor(
        @Optional() @SkipSelf() parentModule: GraphqlModule,
        graphql: Graphql,
        httpLink: HttpLink,
        serverConfigs: ServerConfigs,
        graphqlConfigs: GraphqlConfigs
    ) {

        // Making sure this is not imported twice.
        // https://angular.io/guide/ngmodule#prevent-reimport-of-the-coremodule
        if (parentModule) {
            throw new Error(
                'GraphqlModule is already loaded. Import it in the '+CoreModule.name+' only.');
        }

        // Gql setup:


        const gqlHttpLink = httpLink.create({
            uri: GraphqlModule.buildEndpointUrl(serverConfigs, graphqlConfigs)
        });

        graphql.create({
            link: gqlHttpLink,
            cache: new InMemoryCache(),
        });
    }

    private static buildEndpointUrl(serverConfigs: ServerConfigs, graphqlConfigs: GraphqlConfigs): string {

        return graphqlConfigs.EndpointProtocol +                            // eg. http://
            serverConfigs.ServerDomain+":"+serverConfigs.ServerPort+'/' +   // eg. example.com:80/
            graphqlConfigs.EndpointName;                                    // eg. graphql
    }
}

1 个答案:

答案 0 :(得分:2)

Graphql已在GraphqlModule构造函数中实例化为根注入器,并且GraphqlModule在TestBed imports中指定时会被急切地实例化。没有涉及延迟加载。

正如this answer中所述,TestBed注入器在第一次inject回拨电话或TestBed.getTestBed.createComponent电话上实例化。注射器在第一次注射之前不存在,因此不要有任何模块或提供者实例。由于几乎所有TestBed测试都会在itbeforeEach中至少执行其中一项调用,因此通常不会出现此问题。

由于此测试中不需要graphql实例,为了使测试通过,它可以只是:

TestBed.get(Injector);

或者:

TestBed.get(TestBed);

此外,.compileComponents().then(() => { ... })done()是不必要的,测试不涉及组件并且是同步的。

需要手动实例化注入器的事实表明此测试不需要TestBed,尽管它有用,因为可以测试GraphqlModule构造函数DI注释,包括{{1}的注释}。